triangle_mesh.template.cc
Go to the documentation of this file.
1 //LIC// ====================================================================
2 //LIC// This file forms part of oomph-lib, the object-oriented,
3 //LIC// multi-physics finite-element library, available
4 //LIC// at http://www.oomph-lib.org.
5 //LIC//
6 //LIC// Version 1.0; svn revision $LastChangedRevision$
7 //LIC//
8 //LIC// $LastChangedDate$
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 #ifndef OOMPH_TRIANGLE_MESH_TEMPLATE_CC
31 #define OOMPH_TRIANGLE_MESH_TEMPLATE_CC
32 
33 #include <iostream>
34 
35 #include "triangle_mesh.template.h"
36 #include "../generic/map_matrix.h"
37 #include "../generic/multi_domain.h"
38 #include "../generic/projection.h"
39 #include "../generic/face_element_as_geometric_object.h"
40 
41 namespace oomph
42 {
43 
44  //======================================================================
45  /// Build with the help of the scaffold mesh coming
46  /// from the triangle mesh generator Triangle.
47  //======================================================================
48  template<class ELEMENT>
50  const bool &use_attributes)
51  {
52  // Mesh can only be built with 2D Telements.
53  MeshChecker::assert_geometric_element<TElementGeometricBase,ELEMENT>(2);
54 
55  // Create space for elements
56  unsigned nelem = Tmp_mesh_pt->nelement();
57  Element_pt.resize(nelem);
58 
59  // Create space for nodes
60  unsigned nnode_scaffold = Tmp_mesh_pt->nnode();
61 
62  // Create a map storing the node_id of the mesh used to update the
63  // node position in the update_triangulateio function
64  std::map<Node*, unsigned> old_global_number;
65 
66  // Store the TriangulateIO node id
67  for (unsigned inod = 0; inod < nnode_scaffold; inod++)
68  {
69  Node* old_node_pt = Tmp_mesh_pt->node_pt(inod);
70  old_global_number[old_node_pt] = inod;
71  }
72 
73  // Initialize the old node id vector
74  Oomph_vertex_nodes_id.resize(nnode_scaffold);
75 
76  // Create space for nodes
77  Node_pt.resize(nnode_scaffold, 0);
78 
79  // Set number of boundaries
80  unsigned nbound = Tmp_mesh_pt->nboundary();
81 
82  // Resize the boundary information
83  set_nboundary(nbound);
84  Boundary_element_pt.resize(nbound);
85  Face_index_at_boundary.resize(nbound);
86 
87  //If we have different regions, then resize the region
88  //information
89  if (use_attributes)
90  {
91  Boundary_region_element_pt.resize(nbound);
92  Face_index_region_at_boundary.resize(nbound);
93  }
94 
95  // Loop over elements in scaffold mesh, visit their nodes
96  for (unsigned e = 0; e < nelem; e++)
97  {
98  Element_pt[e] = new ELEMENT;
99  }
100 
101  //Number of nodes per element from the scaffold mesh
102  unsigned nnod_el = Tmp_mesh_pt->finite_element_pt(0)->nnode();
103 
104  // Setup map to check the (pseudo-)global node number
105  // Nodes whose number is zero haven't been copied across
106  // into the mesh yet.
107  std::map<Node*, unsigned> global_number;
108  unsigned global_count = 0;
109 
110  // Map of Element attribute pairs
111  std::map<double, Vector<FiniteElement*> > element_attribute_map;
112 
113  // If we're using attributes
114  if (use_attributes)
115  {
116  // If we're using attributes then we need attribute 0 which will
117  // be associated with region 0
118  element_attribute_map[0].resize(0);
119  }
120 
121  // Loop over elements in scaffold mesh, visit their nodes
122  for (unsigned e = 0; e < nelem; e++)
123  {
124  // Loop over all nodes in element
125  for (unsigned j = 0; j < nnod_el; j++)
126  {
127  // Pointer to node in the scaffold mesh
128  Node* scaffold_node_pt = Tmp_mesh_pt->finite_element_pt(e)->node_pt(j);
129 
130  // Get the (pseudo-)global node number in scaffold mesh
131  // (It's zero [=default] if not visited this one yet)
132  unsigned j_global = global_number[scaffold_node_pt];
133 
134  // Haven't done this one yet
135  if (j_global == 0)
136  {
137  // Find and store the node_id in the old nodes map
138  Oomph_vertex_nodes_id[global_count] =
139  old_global_number[scaffold_node_pt];
140 
141  // Get pointer to set of mesh boundaries that this
142  // scaffold node occupies; NULL if the node is not on any boundary
143  std::set<unsigned>* boundaries_pt;
144  scaffold_node_pt->get_boundaries_pt(boundaries_pt);
145 
146  //Storage for the new node
147  Node* new_node_pt = 0;
148 
149  //Is it on boundaries
150  if (boundaries_pt != 0)
151  {
152  //Create new boundary node
153  new_node_pt=
154  finite_element_pt(e)->construct_boundary_node(j,time_stepper_pt);
155 
156  // Add to boundaries
157  for (std::set<unsigned>::iterator it = boundaries_pt->begin(); it
158  != boundaries_pt->end(); ++it)
159  {
160  add_boundary_node(*it, new_node_pt);
161  }
162  }
163  //Build normal node
164  else
165  {
166  //Create new normal node
167  new_node_pt = finite_element_pt(e)->construct_node(j,time_stepper_pt);
168  }
169 
170  // Give it a number (not necessarily the global node
171  // number in the scaffold mesh -- we just need something
172  // to keep track...)
173  global_count++;
174  global_number[scaffold_node_pt] = global_count;
175 
176  // Copy new node, created using the NEW element's construct_node
177  // function into global storage, using the same global
178  // node number that we've just associated with the
179  // corresponding node in the scaffold mesh
180  Node_pt[global_count - 1] = new_node_pt;
181 
182  // Assign coordinates
183  for (unsigned i = 0; i < finite_element_pt(e)->dim(); i++)
184  {
185  new_node_pt->x(i) = scaffold_node_pt->x(i);
186  }
187  }
188  // This one has already been done: Copy accross
189  else
190  {
191  finite_element_pt(e)->node_pt(j) = Node_pt[j_global - 1];
192  }
193  }
194 
195  // If we're using attributes
196  if (use_attributes)
197  {
198  element_attribute_map[Tmp_mesh_pt->element_attribute(e)].push_back(
199  finite_element_pt(e));
200  }
201  }
202 
203  //Now let's construct lists
204  //Find the number of attributes
205  if (use_attributes)
206  {
207  unsigned n_attribute = element_attribute_map.size();
208 
209  //There are n_attribute different regions
210  this->Region_attribute.resize(n_attribute);
211 
212  //Copy the vectors in the map over to our internal storage
213  unsigned count = 0;
214  for (std::map<double, Vector<FiniteElement*> >::iterator it =
215  element_attribute_map.begin(); it!=element_attribute_map.end(); ++it)
216  {
217  this->Region_attribute[count] = it->first;
218  Region_element_pt[static_cast<unsigned>(Region_attribute[count])] =
219  it->second;
220  ++count;
221  }
222 
223  }
224 
225  // At this point we've created all the elements and
226  // created their vertex nodes. Now we need to create
227  // the additional (midside and internal) nodes!
228 
229  unsigned boundary_id=0;
230 
231  // Get number of nodes along element edge and dimension of element (2)
232  // from first element
233  unsigned n_node_1d = finite_element_pt(0)->nnode_1d();
234  unsigned dim = finite_element_pt(0)->dim();
235 
236  // Storage for the local coordinate of the new node
237  Vector<double> s(dim);
238 
239  // Get number of nodes in the element from first element
240  unsigned n_node = finite_element_pt(0)->nnode();
241 
242  //Storage for each global edge of the mesh
243  unsigned n_global_edge = Tmp_mesh_pt->nglobal_edge();
244  Vector < Vector<Node*> > nodes_on_global_edge(n_global_edge);
245 
246  // Loop over elements
247  for (unsigned e = 0; e < nelem; e++)
248  {
249  //Cache pointers to the elements
250  FiniteElement* const elem_pt = finite_element_pt(e);
251  FiniteElement* const tmp_elem_pt = Tmp_mesh_pt->finite_element_pt(e);
252 
253  //The number of edge nodes is 3*(nnode_1d-1)
254  unsigned n_edge_node = 3 * (n_node_1d - 1);
255 
256  //If there are any more nodes, these are internal and can be
257  //constructed and added directly to the mesh
258  for (unsigned n = n_edge_node; n < n_node; ++n)
259  {
260  // Create new node (it can never be a boundary node)
261  Node* new_node_pt = elem_pt->construct_node(n, time_stepper_pt);
262 
263  // What are the node's local coordinates?
264  elem_pt->local_coordinate_of_node(n, s);
265 
266  // Find the coordinates of the new node from the existing
267  // and fully-functional element in the scaffold mesh
268  for (unsigned i = 0; i < dim; i++)
269  {
270  new_node_pt->x(i) = tmp_elem_pt->interpolated_x(s, i);
271  }
272 
273  //Add the node to the mesh's global look-up scheme
274  Node_pt.push_back(new_node_pt);
275  }
276 
277  //Now loop over the mid-side edge nodes
278  //Start from node number 3
279  unsigned n = 3;
280 
281  // Loop over edges
282  for (unsigned j = 0; j < 3; j++)
283  {
284  //Find the boundary id of the edge
285  boundary_id = Tmp_mesh_pt->edge_boundary(e, j);
286 
287  //Find the global edge index
288  unsigned edge_index = Tmp_mesh_pt->edge_index(e, j);
289 
290  //If the nodes on the edge have not been allocated, construct them
291  if (nodes_on_global_edge[edge_index].size() == 0)
292  {
293  //Loop over the nodes on the edge excluding the ends
294  for (unsigned j2 = 0; j2 < n_node_1d - 2; ++j2)
295  {
296  //Storage for the new node
297  Node* new_node_pt = 0;
298 
299  //If the edge is on a boundary, construct a boundary node
300  if (boundary_id > 0)
301  {
302  new_node_pt = elem_pt->construct_boundary_node(n, time_stepper_pt);
303  //Add it to the boundary
304  this->add_boundary_node(boundary_id - 1, new_node_pt);
305  }
306  //Otherwise construct a normal node
307  else
308  {
309  new_node_pt = elem_pt->construct_node(n, time_stepper_pt);
310  }
311 
312  // What are the node's local coordinates?
313  elem_pt->local_coordinate_of_node(n, s);
314 
315  // Find the coordinates of the new node from the existing
316  // and fully-functional element in the scaffold mesh
317  for (unsigned i = 0; i < dim; i++)
318  {
319  new_node_pt->x(i) = tmp_elem_pt->interpolated_x(s, i);
320  }
321 
322  //Add to the global node list
323  Node_pt.push_back(new_node_pt);
324 
325  //Add to the edge index
326  nodes_on_global_edge[edge_index].push_back(new_node_pt);
327  //Increment the node number
328  ++n;
329  }
330  }
331  //Otherwise just set the pointers
332  //using the fact that the next time the edge is visited
333  //the nodes must be arranged in the other order because all
334  //triangles have the same orientation
335  else
336  {
337  //Loop over the nodes on the edge excluding the ends
338  for (unsigned j2 = 0; j2 < n_node_1d - 2; ++j2)
339  {
340  //Set the local node from the edge but indexed the other
341  //way around
342  elem_pt->node_pt(n) = nodes_on_global_edge[edge_index][n_node_1d - 3
343  - j2];
344  ++n;
345  }
346  }
347 
348  //Set the elements adjacent to the boundary from the
349  //boundary id information
350  if (boundary_id > 0)
351  {
352  Boundary_element_pt[boundary_id - 1].push_back(elem_pt);
353  //Need to put a shift in here because of an inconsistent naming
354  //convention between triangle and face elements
355  Face_index_at_boundary[boundary_id - 1].push_back((j + 2) % 3);
356 
357  //If using regions set up the boundary information
358  if (use_attributes)
359  {
360  unsigned tmp_region =
361  static_cast<unsigned> (Tmp_mesh_pt->element_attribute(e));
362  //Element adjacent to boundary
363  Boundary_region_element_pt[boundary_id - 1]
364  [tmp_region].push_back(elem_pt);
365  //Need to put a shift in here because of an inconsistent naming
366  //convention between triangle and face elements
367  Face_index_region_at_boundary[boundary_id - 1]
368  [tmp_region].push_back((j + 2) % 3);
369  }
370  }
371 
372  } //end of loop over edges
373  } //end of loop over elements
374 
375 
376  // Lookup scheme has now been setup
377  Lookup_for_elements_next_boundary_is_setup = true;
378 
379  }
380 
381 #ifdef OOMPH_HAS_MPI
382 
383  //======================================================================
384  /// \short Identify the segments from the old mesh (original mesh)
385  /// in the new mesh (this) and assign initial and final boundary
386  /// coordinates for the segments that create the boundary
387  //======================================================================
388  template<class ELEMENT>
391  const unsigned& b, TriangleMesh<ELEMENT>* original_mesh_pt)
392  {
393  // ------------------------------------------------------------------
394  // First: Get the face elements associated with the current boundary
395  // (nonhalo elements only)
396  // ------------------------------------------------------------------
397  // Temporary storage for face elements
398  Vector<FiniteElement*> face_el_pt;
399 
400  // Temporary storage for number of elements adjacent to the boundary
401  unsigned nele = 0;
402 
403  // Temporary storage for elements adjacent to the boundary that have
404  // a common edge (related with internal boundaries)
405  unsigned n_repeated_ele = 0;
406 
407  const unsigned n_regions = this->nregion();
408 
409  // map to associate the face element to the bulk element, necessary
410  // to attach halo face elements at both sides of each found segment
411  std::map<FiniteElement*,FiniteElement*> face_to_bulk_element_pt;
412 
413  // Temporary storage for already done nodes
414  Vector<std::pair<Node*, Node*> > done_nodes_pt;
415 
416  // If there is more than one region then only use boundary
417  // coordinates from the bulk side (region 0)
418  if (n_regions > 1)
419  {
420  for (unsigned rr = 0 ; rr < n_regions; rr++)
421  {
422  const unsigned region_id =
423  static_cast<unsigned>(this->Region_attribute[rr]);
424 
425  // Loop over all elements on boundaries in region i_r
426  const unsigned nel_in_region =
427  this->nboundary_element_in_region(b, region_id);
428 
429  unsigned nel_repetead_in_region = 0;
430 
431  // Only bother to do anything else, if there are elements
432  // associated with the boundary and the current region
433  if (nel_in_region > 0)
434  {
435  // Flag that activates when a repeated face element is found,
436  // possibly because we are dealing with an internal boundary
437  bool repeated = false;
438 
439  // Loop over the bulk elements adjacent to boundary b
440  for (unsigned e = 0; e < nel_in_region; e++)
441  {
442  // Get pointer to the bulk element that is adjacent to boundary b
443  FiniteElement* bulk_elem_pt =
444  this->boundary_element_in_region_pt(b, region_id, e);
445 
446 #ifdef OOMPH_HAS_MPI
447  // In a distributed mesh only work with nonhalo elements
448  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
449  {
450  // Increase the number of repeated elements
451  n_repeated_ele++;
452  // Go for the next element
453  continue;
454  }
455 #endif
456 
457  //Find the index of the face of element e along boundary b
458  int face_index =
459  this->face_index_at_boundary_in_region(b,region_id,e);
460 
461  // Before adding the new element we need to be sure that
462  // the edge that this element represent has not been
463  // already added
464  FiniteElement* tmp_ele_pt =
465  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
466 
467  const unsigned n_nodes = tmp_ele_pt->nnode();
468 
469  std::pair<Node*, Node*> tmp_pair =
470  std::make_pair(tmp_ele_pt->node_pt(0),
471  tmp_ele_pt->node_pt(n_nodes - 1));
472 
473  std::pair<Node*, Node*> tmp_pair_inverse =
474  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
475  tmp_ele_pt->node_pt(0));
476 
477  // Search for repeated nodes
478  const unsigned n_done_nodes = done_nodes_pt.size();
479  for (unsigned l = 0; l < n_done_nodes; l++)
480  {
481  if (tmp_pair == done_nodes_pt[l] ||
482  tmp_pair_inverse == done_nodes_pt[l])
483  {
484  nel_repetead_in_region++;
485  repeated = true;
486  break;
487  }
488  }
489 
490  // Create new face element
491  if (!repeated)
492  {
493  // Add the pair of nodes (edge) to the node dones
494  done_nodes_pt.push_back(tmp_pair);
495  // Create the map to know if the element is halo
496  face_el_pt.push_back(tmp_ele_pt);
497  // Add the element to the face elements
498  face_to_bulk_element_pt[tmp_ele_pt] = bulk_elem_pt;
499  }
500  else
501  {
502  // Clean up
503  delete tmp_ele_pt;
504  tmp_ele_pt = 0;
505  }
506 
507  // Re-start
508  repeated = false;
509 
510  } // for (e < nel_in_region)
511 
512  nele += nel_in_region;
513 
514  n_repeated_ele += nel_repetead_in_region;
515 
516  } // if (nel_in_region > 0)
517  } // for (rr < n_regions)
518  } // if (n_regions > 1)
519  //Otherwise it's just the normal boundary functions
520  else
521  {
522  // Loop over all elements on boundaries
523  nele = this->nboundary_element(b);
524 
525  //Only bother to do anything else, if there are elements
526  if (nele > 0)
527  {
528  // Flag that activates when a repeated face element is found,
529  // possibly because we are dealing with an internal boundary
530  bool repeated = false;
531 
532  // Loop over the bulk elements adjacent to boundary b
533  for (unsigned e = 0; e < nele; e++)
534  {
535  // Get pointer to the bulk element that is adjacent to boundary b
536  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
537 
538 #ifdef OOMPH_HAS_MPI
539  // In a distributed mesh only work with nonhalo elements
540  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
541  {
542  // Increase the number of repeated elements
543  n_repeated_ele++;
544  // Go for the next element
545  continue;
546  }
547 #endif
548 
549  //Find the index of the face of element e along boundary b
550  int face_index = this->face_index_at_boundary(b, e);
551 
552  // Before adding the new element we need to be sure that
553  // the edge that this element represents has not been
554  // already added (only applies for internal boundaries)
555  FiniteElement* tmp_ele_pt =
556  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
557 
558  const unsigned n_nodes = tmp_ele_pt->nnode();
559 
560  std::pair<Node*, Node*> tmp_pair =
561  std::make_pair(tmp_ele_pt->node_pt(0),
562  tmp_ele_pt->node_pt(n_nodes - 1));
563 
564  std::pair<Node*, Node*> tmp_pair_inverse =
565  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
566  tmp_ele_pt->node_pt(0));
567 
568  // Search for repeated nodes
569  const unsigned n_done_nodes = done_nodes_pt.size();
570  for (unsigned l = 0; l < n_done_nodes; l++)
571  {
572  if (tmp_pair == done_nodes_pt[l] ||
573  tmp_pair_inverse == done_nodes_pt[l])
574  {
575  // Increase the number of repeated elements
576  n_repeated_ele++;
577  // Mark the element as repeated
578  repeated = true;
579  break;
580  }
581  }
582 
583  // Create new face element
584  if (!repeated)
585  {
586  // Add the pair of nodes (edge) to the node dones
587  done_nodes_pt.push_back(tmp_pair);
588  // Add the element to the face elements
589  face_el_pt.push_back(tmp_ele_pt);
590  // Create the map to know if the element is halo
591  face_to_bulk_element_pt[tmp_ele_pt] = bulk_elem_pt;
592  }
593  else
594  {
595  // Free the repeated bulk element!!
596  delete tmp_ele_pt;
597  tmp_ele_pt = 0;
598  }
599 
600  // Re-start
601  repeated = false;
602 
603  } // for (e < nel)
604  } // if (nel > 0)
605 
606  } // else (n_regions > 1)
607 
608  // Do not consider the repeated elements
609  nele-= n_repeated_ele;
610 
611 #ifdef PARANOID
612  if (nele!=face_el_pt.size())
613  {
614  std::ostringstream error_message;
615  error_message
616  << "The independent counting of face elements ("<<nele<<") for "
617  << "boundary ("<<b<<") is different\n"
618  << "from the real number of face elements in the container ("
619  << face_el_pt.size() <<")\n";
620  throw OomphLibError(error_message.str(),
621  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
622  OOMPH_EXCEPTION_LOCATION);
623  }
624 #endif
625 
626  // Continue even thought there are no elements, the processor needs
627  // to participate in the communications
628 
629  // ----------------------------------------------------------------
630  // Second: Sort the face elements, only consider nonhalo elements
631  // ----------------------------------------------------------------
632 
633  // A flag vector to mark those face elements that are considered as
634  // halo in the current processor
635  std::vector<bool> is_halo_face_element(nele,false);
636 
637  // Count the total number of non halo face elements
638  unsigned nnon_halo_face_elements = 0;
639 
640  // We will have halo face elements if the mesh is distributed
641  for (unsigned ie = 0; ie < nele; ie++)
642  {
643  // Get the face element
644  FiniteElement* face_ele_pt = face_el_pt[ie];
645  // Get the bulk element
646  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_ele_pt];
647  // Check if the bulk element is halo
648  if (!tmp_bulk_ele_pt->is_halo())
649  {
650  is_halo_face_element[ie] = false;
651  nnon_halo_face_elements++;
652  }
653  else
654  {
655  // Mark the face element as halo
656  is_halo_face_element[ie] = true;
657  }
658  } // for (ie < nele)
659 
660 #ifdef PARANOID
661  // Get the total number of halo face elements
662  const unsigned nhalo_face_element = nele - nnon_halo_face_elements;
663  if (nhalo_face_element > 0)
664  {
665  std::ostringstream error_message;
666  error_message
667  << "There should not be halo face elements since they were not "
668  << "considered when computing the face elements\n\n"
669  << "The number of found halo face elements is: "
670  << nhalo_face_element << "\n\n";
671  throw OomphLibError(error_message.str(),
672  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
673  OOMPH_EXCEPTION_LOCATION);
674  }
675 #endif
676 
677  // The vector of list to store the "segments" that compound the
678  // boundary (segments may appear only in a distributed mesh)
679  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
680 
681  // Number of already sorted face elements (only nonhalo elements for
682  // a distributed mesh)
683  unsigned nsorted_face_elements = 0;
684 
685  // Keep track of who's done (this apply to nonhalo only, remember we
686  // are only working with nonhalo elements)
687  std::map<FiniteElement*, bool> done_el;
688 
689  // Keep track of which element is inverted (in distributed mesh the
690  // elements may be inverted with respect to the segment they belong)
691  std::map<FiniteElement*, bool> is_inverted;
692 
693  // Iterate until all possible segments have been created
694  while(nsorted_face_elements < nnon_halo_face_elements)
695  {
696  // The ordered list of face elements (in a distributed mesh a
697  // collection of contiguous face elements define a segment)
698  std::list<FiniteElement*> sorted_el_pt;
699  sorted_el_pt.clear();
700 
701 #ifdef PARANOID
702  // Select an initial element for the segment
703  bool found_initial_face_element = false;
704 #endif
705 
706  FiniteElement* ele_face_pt = 0;
707 
708  unsigned iface = 0;
709  for (iface = 0; iface < nele; iface++)
710  {
711  if (!is_halo_face_element[iface])
712  {
713  ele_face_pt = face_el_pt[iface];
714  // If not done then take it as initial face element
715  if (!done_el[ele_face_pt])
716  {
717 #ifdef PARANOID
718  found_initial_face_element = true;
719 #endif
720  nsorted_face_elements++;
721  iface++; // The next element number
722  sorted_el_pt.push_back(ele_face_pt);
723  // Mark as done
724  done_el[ele_face_pt] = true;
725  break;
726  }
727  }
728  } // for (iface < nele)
729 
730 #ifdef PARANOID
731  if (!found_initial_face_element)
732  {
733  std::ostringstream error_message;
734  error_message
735  <<"Could not find an initial face element for the current segment\n";
736  throw OomphLibError(error_message.str(),
737  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
738  OOMPH_EXCEPTION_LOCATION);
739  }
740 #endif
741 
742  // Number of nodes
743  const unsigned nnod = ele_face_pt->nnode();
744 
745  // Left and right most nodes (the left and right nodes of the
746  // current face element)
747  Node* left_node_pt = ele_face_pt->node_pt(0);
748  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
749 
750  // Continue iterating if a new face element has been added to the
751  // list
752  bool face_element_added = false;
753 
754  // While a new face element has been added to the set of sorted
755  // face elements then re-iterate
756  do
757  {
758  // Start from the next face element since we have already added
759  // the previous one as the initial face element (any previous
760  // face element had to be added on previous iterations)
761  for (unsigned iiface = iface; iiface < nele; iiface++)
762  {
763  // Re-start flag
764  face_element_added = false;
765 
766  // Get the candidate element
767  ele_face_pt = face_el_pt[iiface];
768 
769  // Check that the candidate element has not been done and is
770  // not a halo element
771  if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
772  {
773  // Get the left and right nodes of the current element
774  Node* local_left_node_pt = ele_face_pt->node_pt(0);
775  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
776  // New element fits at the left of segment and is not inverted
777  if (left_node_pt == local_right_node_pt)
778  {
779  left_node_pt = local_left_node_pt;
780  sorted_el_pt.push_front(ele_face_pt);
781  is_inverted[ele_face_pt] = false;
782  face_element_added = true;
783  }
784  // New element fits at the left of segment and is inverted
785  else if (left_node_pt == local_left_node_pt)
786  {
787  left_node_pt = local_right_node_pt;
788  sorted_el_pt.push_front(ele_face_pt);
789  is_inverted[ele_face_pt] = true;
790  face_element_added = true;
791  }
792  // New element fits on the right of segment and is not inverted
793  else if (right_node_pt == local_left_node_pt)
794  {
795  right_node_pt = local_right_node_pt;
796  sorted_el_pt.push_back(ele_face_pt);
797  is_inverted[ele_face_pt] = false;
798  face_element_added = true;
799  }
800  // New element fits on the right of segment and is inverted
801  else if (right_node_pt == local_right_node_pt)
802  {
803  right_node_pt = local_left_node_pt;
804  sorted_el_pt.push_back(ele_face_pt);
805  is_inverted[ele_face_pt] = true;
806  face_element_added = true;
807  }
808 
809  if (face_element_added)
810  {
811  done_el[ele_face_pt] = true;
812  nsorted_face_elements++;
813  break;
814  }
815 
816  } // if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
817  } // for (iiface<nnon_halo_face_element)
818  }while(face_element_added &&
819  (nsorted_face_elements < nnon_halo_face_elements));
820 
821  // Store the created segment in the vector of segments
822  segment_sorted_ele_pt.push_back(sorted_el_pt);
823 
824  } // while(nsorted_face_elements < nnon_halo_face_elements);
825 
826  // The number of segments in this processor
827  const unsigned nsegments = segment_sorted_ele_pt.size();
828 
829  // ------------------------------------------------------------------
830  // Third: We have the face elements sorted (nonhalo only), now
831  // assign boundary coordinates to the nodes in the segments. This is
832  // the LOCAL boundary coordinate which is required if the zeta
833  // values need to be inverted
834  // ------------------------------------------------------------------
835  // Necessary in case boundaries with no geom object associated need
836  // to be inverted the zeta values (It is necessary to compute the
837  // arclength but also to store the nodes in a container (set))
838  // ------------------------------------------------------------------
839 
840  // Vector of sets that stores the nodes of each segment based on a
841  // lexicographically order starting from the bottom left node of
842  // each segment
843  Vector<std::set<Node*> > segment_all_nodes_pt;
844 
845  // The arclength of each segment in the current processor
846  Vector<double> segment_arclength(nsegments);
847 
848  // The number of vertices of each segment
849  Vector<unsigned> nvertices_per_segment(nsegments);
850 
851  // The initial zeta for the segment
852  Vector<double> initial_zeta_segment(nsegments);
853 
854  // The final zeta for the segment
855  Vector<double> final_zeta_segment(nsegments);
856 
857 #ifdef PARANOID
858  if (nnon_halo_face_elements > 0 && nsegments == 0)
859  {
860  std::ostringstream error_message;
861  error_message
862  << "The number of segments is zero, but the number of nonhalo\n"
863  << "elements is: (" << nnon_halo_face_elements << ")\n";
864  throw OomphLibError(error_message.str(),
865  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
866  OOMPH_EXCEPTION_LOCATION);
867  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
868 #endif
869 
870  // Go through all the segments and compute the LOCAL boundary
871  // coordinates
872  for (unsigned is = 0; is < nsegments; is++)
873  {
874 #ifdef PARANOID
875  if (segment_sorted_ele_pt[is].size() == 0)
876  {
877  std::ostringstream error_message;
878  error_message
879  << "The (" << is << ")-th segment has no elements\n";
880  throw OomphLibError(error_message.str(),
881  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
882  OOMPH_EXCEPTION_LOCATION);
883  } // if (segment_sorted_ele_pt[is].size() == 0)
884 #endif
885 
886  // Get access to the first element on the segment
887  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
888 
889  // Number of nodes
890  const unsigned nnod = first_ele_pt->nnode();
891 
892  // Get the first node of the current segment
893  Node *first_node_pt = first_ele_pt->node_pt(0);
894  if (is_inverted[first_ele_pt])
895  {
896  first_node_pt = first_ele_pt->node_pt(nnod-1);
897  }
898 
899  // Get access to the last element on the segment
900  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
901 
902  // Get the last node of the current segment
903  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
904  if (is_inverted[last_ele_pt])
905  {
906  last_node_pt = last_ele_pt->node_pt(0);
907  }
908 
909  // Coordinates of left node
910  double x_left = first_node_pt->x(0);
911  double y_left = first_node_pt->x(1);
912 
913  // Initialise boundary coordinate (local boundary coordinate for
914  // boundaries with more than one segment)
915  Vector<double> zeta(1, 0.0);
916 
917  // If the boundary has an associated GeomObject then it is not
918  // necessary to compute the arclength, only read the values from
919  // the nodes at the edges
920  if (this->boundary_geom_object_pt(b)!=0)
921  {
922  first_node_pt->get_coordinates_on_boundary(b, zeta);
923  initial_zeta_segment[is] = zeta[0];
924  last_node_pt->get_coordinates_on_boundary(b, zeta);
925  final_zeta_segment[is] = zeta[0];
926  }
927 
928  // Lexicographically bottom left node
929  std::set<Node*> local_nodes_pt;
930  local_nodes_pt.insert(first_node_pt);
931 
932  // Now loop over nodes in order
933  for (std::list<FiniteElement*>::iterator it =
934  segment_sorted_ele_pt[is].begin();
935  it != segment_sorted_ele_pt[is].end(); it++)
936  {
937  // Get element
938  FiniteElement* el_pt = *it;
939 
940  // Start node and increment
941  unsigned k_nod = 1;
942  int nod_diff = 1;
943  if (is_inverted[el_pt])
944  {
945  k_nod = nnod - 2;
946  nod_diff = -1;
947  }
948 
949  // Loop over nodes
950  for (unsigned j = 1; j < nnod; j++)
951  {
952  Node* nod_pt = el_pt->node_pt(k_nod);
953  k_nod += nod_diff;
954 
955  // Coordinates of right node
956  double x_right = nod_pt->x(0);
957  double y_right = nod_pt->x(1);
958 
959  // Increment boundary coordinate (the arclength)
960  zeta[0] += sqrt(
961  (x_right - x_left) * (x_right - x_left) + (y_right - y_left)
962  * (y_right - y_left));
963 
964  // // When we have a GeomObject associated to the boundary we already
965  // // know the zeta values for the nodes, there is no need to compute
966  // // the arclength
967  // if (this->boundary_geom_object_pt(b)==0)
968  // {
969  // // Set boundary coordinate
970  // nod_pt->set_coordinates_on_boundary(b, zeta);
971  // }
972 
973  // Increment reference coordinate
974  x_left = x_right;
975  y_left = y_right;
976 
977  // Get lexicographically bottom left node but only
978  // use vertex nodes as candidates
979  local_nodes_pt.insert(nod_pt);
980  } // for (j < nnod)
981 
982  } // iterator over the elements in the segment
983 
984  // Store the arclength of the segment
985  segment_arclength[is] = zeta[0];
986 
987  // Store the number of vertices in the segment
988  nvertices_per_segment[is] = local_nodes_pt.size();
989 
990  // Add the nodes for the corresponding segment in the container
991  segment_all_nodes_pt.push_back(local_nodes_pt);
992 
993  } // for (is < nsegments)
994 
995  // Get the number of sets for nodes
996 #ifdef PARANOID
997  if (segment_all_nodes_pt.size() != nsegments)
998  {
999  std::ostringstream error_message;
1000  error_message
1001  <<"The number of segments ("<<nsegments<<") and the number of "
1002  <<"sets of nodes ("<<segment_all_nodes_pt.size()<<") representing\n"
1003  <<"the\nsegments is different!!!\n\n";
1004  throw OomphLibError(
1005  error_message.str(),
1006  OOMPH_CURRENT_FUNCTION,
1007  OOMPH_EXCEPTION_LOCATION);
1008  }
1009 #endif
1010 
1011  // Store the initial arclength for each segment of boundary in the
1012  // current processor, initalise to zero in case we have a non
1013  // distributed boundary
1014  Vector<double> initial_segment_arclength(nsegments,0.0);
1015 
1016  // Associated the index of the current segment to the segment index
1017  // in the original mesh (input mesh)
1018  Vector<unsigned> current_segment_to_original_segment_index(nsegments);
1019 
1020  // Each segment needs to know whether it has to be inverted or not
1021  // Store whether a segment needs to be inverted or not
1022  Vector<unsigned> segment_inverted(nsegments);
1023 
1024  // -----------------------------------------------------------------
1025  // Fourth: Identify the segments with the ones in the original mesh
1026  // (has sense only in the adaptation process)
1027  // -----------------------------------------------------------------
1028 
1029  // Now check if there are segments associated to this boundary
1030  if (nsegments > 0)
1031  {
1032 #ifdef PARANOID
1033  // Double check that the same number of coordinates (nsegments)
1034  // have been established for the boundary
1035  const unsigned nsegments_initial_coordinates =
1036  original_mesh_pt->boundary_segment_initial_coordinate(b).size();
1037 
1038  const unsigned nsegments_final_coordinates =
1039  original_mesh_pt->boundary_segment_final_coordinate(b).size();
1040 
1041  if (nsegments_initial_coordinates!=nsegments_final_coordinates)
1042  {
1043  std::stringstream error_message;
1044  error_message
1045  <<"The number of segments that present initial coordinates "
1046  <<nsegments_initial_coordinates<<" is different from "
1047  <<"the\nnumber of segments that present final coordinates "
1048  <<nsegments_final_coordinates<<"\n\n";
1049  throw OomphLibError(
1050  error_message.str(),
1051  OOMPH_CURRENT_FUNCTION,
1052  OOMPH_EXCEPTION_LOCATION);
1053  } // if (nsegments_initial_coordinates!=nsegments_final_coordinates)
1054 
1055  // Also check that the number of segments found in the previous
1056  // mesh is the same as the number of segments found in this mesh
1057  if (nsegments_initial_coordinates != nsegments)
1058  {
1059  std::stringstream error_message;
1060  error_message
1061  <<"Working with boundary ("<< b << ").\n The number of initial and "
1062  <<"final coordinates ("
1063  <<nsegments_initial_coordinates<<") is different from\n"
1064  <<"the number of found segments ("<< nsegments <<").\n\n";
1065  throw OomphLibError(
1066  error_message.str(),
1067  OOMPH_CURRENT_FUNCTION,
1068  OOMPH_EXCEPTION_LOCATION);
1069  } // if (nsegments_initial_coordinates != nsegments)
1070 #endif
1071 
1072  // Create a backup for the data from the original mesh
1073  // Backup for the coordinates
1074  Vector<Vector<double> >original_mesh_segment_initial_coordinate(nsegments);
1075  Vector<Vector<double> >original_mesh_segment_final_coordinate(nsegments);
1076  // Backup for the zeta values
1077  Vector<double> original_mesh_segment_initial_zeta(nsegments);
1078  Vector<double> original_mesh_segment_final_zeta(nsegments);
1079  // Backup for the arclengths
1080  Vector<double> original_mesh_segment_initial_arclength(nsegments);
1081  Vector<double> original_mesh_segment_final_arclength(nsegments);
1082  // Do the backup
1083  for (unsigned is = 0; is < nsegments; is++)
1084  {
1085  original_mesh_segment_initial_coordinate[is].resize(2);
1086  original_mesh_segment_final_coordinate[is].resize(2);
1087  for (unsigned k = 0; k < 2; k++)
1088  {
1089  original_mesh_segment_initial_coordinate[is][k] =
1090  original_mesh_pt->boundary_segment_initial_coordinate(b)[is][k];
1091  original_mesh_segment_final_coordinate[is][k] =
1092  original_mesh_pt->boundary_segment_final_coordinate(b)[is][k];
1093  }
1094  // Check if the boudary has an associated GeomObject
1095  if (this->boundary_geom_object_pt(b)!=0)
1096  {
1097  original_mesh_segment_initial_zeta[is] =
1098  original_mesh_pt->boundary_segment_initial_zeta(b)[is];
1099  original_mesh_segment_final_zeta[is] =
1100  original_mesh_pt->boundary_segment_final_zeta(b)[is];
1101  }
1102  else
1103  {
1104  original_mesh_segment_initial_arclength[is] =
1105  original_mesh_pt->boundary_segment_initial_arclength(b)[is];
1106  original_mesh_segment_final_arclength[is] =
1107  original_mesh_pt->boundary_segment_final_arclength(b)[is];
1108  }
1109  } // for (is < nsegments)
1110 
1111  // Clear all the storage
1112  Boundary_segment_inverted[b].clear();
1113  Boundary_segment_initial_coordinate[b].clear();
1114  Boundary_segment_final_coordinate[b].clear();
1115 
1116  Boundary_segment_initial_zeta[b].clear();
1117  Boundary_segment_final_zeta[b].clear();
1118 
1119  Boundary_segment_initial_arclength[b].clear();
1120  Boundary_segment_final_arclength[b].clear();
1121 
1122  // Identify each segment in the processor with the ones created
1123  // by the original mesh
1124  // -----------------------------------------------------------------
1125  // Keep track of the already identified segments
1126  std::map<unsigned,bool> segment_done;
1127  for (unsigned is = 0; is < nsegments; is++)
1128  {
1129 #ifdef PARANOID
1130  // Flag to know if the segment was identified
1131  bool found_original_segment = false;
1132 #endif
1133 
1134  // Get the initial and final coordinates of the current segment
1135  Vector<double> current_seg_initial_coord(2);
1136  Vector<double> current_seg_final_coord(2);
1137 
1138  // Get access to the initial element on the segment
1139  FiniteElement* current_seg_initial_ele_pt =
1140  segment_sorted_ele_pt[is].front();
1141 
1142  // Number of nodes
1143  const unsigned nnod = current_seg_initial_ele_pt->nnode();
1144 
1145  // Get the first node of the current segment
1146  Node *current_seg_first_node_pt=
1147  current_seg_initial_ele_pt->node_pt(0);
1148  if (is_inverted[current_seg_initial_ele_pt])
1149  {
1150  current_seg_first_node_pt =
1151  current_seg_initial_ele_pt->node_pt(nnod-1);
1152  }
1153 
1154  // Get access to the last element on the segment
1155  FiniteElement* current_seg_last_ele_pt =
1156  segment_sorted_ele_pt[is].back();
1157 
1158  // Get the last node of the current segment
1159  Node *current_seg_last_node_pt =
1160  current_seg_last_ele_pt->node_pt(nnod-1);
1161  if (is_inverted[current_seg_last_ele_pt])
1162  {
1163  current_seg_last_node_pt =
1164  current_seg_last_ele_pt->node_pt(0);
1165  }
1166 
1167  // Get the coordinates for the first and last seg node
1168  for (unsigned i = 0; i < 2; i++)
1169  {
1170  current_seg_initial_coord[i]=current_seg_first_node_pt->x(i);
1171  current_seg_final_coord[i]=current_seg_last_node_pt->x(i);
1172  }
1173 
1174  // We have got the initial and final coordinates of the current
1175  // segment, compare those with the initial and final coordinates
1176  // of the original mesh segments to identify which segments is
1177  // which
1178  for (unsigned orig_s = 0; orig_s < nsegments; orig_s++)
1179  {
1180  if (!segment_done[orig_s])
1181  {
1182  // Get the coordinates to compare
1183  Vector<double> initial_coordinate =
1184  original_mesh_segment_initial_coordinate[orig_s];
1185  Vector<double> final_coordinate =
1186  original_mesh_segment_final_coordinate[orig_s];
1187 
1188  // Compute the distance initial(current)-initial(original)
1189  // coordinates
1190  double dist =
1191  ((current_seg_initial_coord[0] - initial_coordinate[0])*
1192  (current_seg_initial_coord[0] - initial_coordinate[0]))
1193  +
1194  ((current_seg_initial_coord[1] - initial_coordinate[1])*
1195  (current_seg_initial_coord[1] - initial_coordinate[1]));
1196  dist = sqrt(dist);
1197 
1198  // If the initial node is the same, check for the last node
1199  if (dist <
1201  {
1202  // Compute the distance final(current)-final(original)
1203  // coordinates
1204  dist =
1205  ((current_seg_final_coord[0] - final_coordinate[0])*
1206  (current_seg_final_coord[0] - final_coordinate[0]))
1207  +
1208  ((current_seg_final_coord[1] - final_coordinate[1])*
1209  (current_seg_final_coord[1] - final_coordinate[1]));
1210  dist = sqrt(dist);
1211 
1212  // The final node is the same, we have identified the
1213  // segments
1214  if (dist <
1216  {
1217  // Store the index that relates the previous index with the
1218  // current one
1219  current_segment_to_original_segment_index[is] = orig_s;
1220 
1221  // In this case the segment is not inverted
1222  Boundary_segment_inverted[b].push_back(0);
1223 
1224  // Copy the initial and final coordinates for each segment
1225  Boundary_segment_initial_coordinate[b].push_back(
1226  initial_coordinate);
1227  Boundary_segment_final_coordinate[b].push_back(
1228  final_coordinate);
1229 
1230  // Check if the boundary has an associated GeomObject
1231  if (this->boundary_geom_object_pt(b)!=0)
1232  {
1233  // Copy the initial zeta value for the segment
1234  Boundary_segment_initial_zeta[b].push_back(
1235  original_mesh_segment_initial_zeta[orig_s]);
1236  Boundary_segment_final_zeta[b].push_back(
1237  original_mesh_segment_final_zeta[orig_s]);
1238  }
1239  else
1240  {
1241  // Copy the initial and final arclength for each
1242  // segment
1243  Boundary_segment_initial_arclength[b].push_back(
1244  original_mesh_segment_initial_arclength[orig_s]);
1245  Boundary_segment_final_arclength[b].push_back(
1246  original_mesh_segment_final_arclength[orig_s]);
1247  }
1248  // Mark the segment as done
1249  segment_done[orig_s] = true;
1250 #ifdef PARANOID
1251  found_original_segment = true;
1252 #endif
1253  break;
1254  } // The final(current) node matched with the
1255  // final(original) node
1256  } // The initial(current) node matched with the
1257  // initial(original) node
1258  else
1259  {
1260  // Check the inverted case Compute the distance
1261  // initial(current)-final(original) coordinates
1262  double dist_inv =
1263  ((current_seg_initial_coord[0] - final_coordinate[0])*
1264  (current_seg_initial_coord[0] - final_coordinate[0]))
1265  +
1266  ((current_seg_initial_coord[1] - final_coordinate[1])*
1267  (current_seg_initial_coord[1] - final_coordinate[1]));
1268  dist_inv = sqrt(dist_inv);
1269 
1270  // If the initial node is the same as the final node of
1271  // the segment, check for the last node
1272  if (dist_inv <
1274  {
1275  // Compute the distance final(current)-initial(original)
1276  // coordinates
1277  dist_inv =
1278  ((current_seg_final_coord[0] - initial_coordinate[0])*
1279  (current_seg_final_coord[0] - initial_coordinate[0]))
1280  +
1281  ((current_seg_final_coord[1] - initial_coordinate[1])*
1282  (current_seg_final_coord[1] - initial_coordinate[1]));
1283  dist_inv = sqrt(dist_inv);
1284 
1285  // The final node is the same as the initial node, we
1286  // have identified the segments
1287  if (dist_inv <
1289  {
1290  // Store the index that related the previous index with the
1291  // current one
1292  current_segment_to_original_segment_index[is] = orig_s;
1293 
1294  // In this case the segment is inverted
1295  Boundary_segment_inverted[b].push_back(1);
1296 
1297  // Copy the initial and final coordinates for each segment
1298  Boundary_segment_initial_coordinate[b].push_back(
1299  initial_coordinate);
1300  Boundary_segment_final_coordinate[b].push_back(
1301  final_coordinate);
1302 
1303  // Check that the boudary has an associated GeomObject
1304  if (this->boundary_geom_object_pt(b)!=0)
1305  {
1306  // Copy the initial zeta value for the segments
1307  Boundary_segment_initial_zeta[b].push_back(
1308  original_mesh_segment_initial_zeta[orig_s]);
1309  Boundary_segment_final_zeta[b].push_back(
1310  original_mesh_segment_final_zeta[orig_s]);
1311  }
1312  else
1313  {
1314  // Copy the initial and final arclength for each segment
1315  Boundary_segment_initial_arclength[b].push_back(
1316  original_mesh_segment_initial_arclength[orig_s]);
1317  Boundary_segment_final_arclength[b].push_back(
1318  original_mesh_segment_final_arclength[orig_s]);
1319  }
1320  // Mark the segment as done
1321  segment_done[orig_s] = true;
1322 #ifdef PARANOID
1323  found_original_segment = true;
1324 #endif
1325  break;
1326  } // The final(current) node matched with the
1327  // initial(original) node
1328  } // The initial(current) node matched with the
1329  // final(original) node
1330  } // else (the first(current) node did not matched with the
1331  // first(original) node. Else do the inverted case
1332 
1333  } // (!segment_done[orig_s])
1334 
1335  } // (orig_s < nsegments)
1336 
1337 #ifdef PARANOID
1338  if (!found_original_segment)
1339  {
1340  std::stringstream error_message;
1341  error_message
1342  <<"The ("<<is<<")-th segment on the current segment was not\n"
1343  << "found when trying to identify it with the original mesh's\n"
1344  << "segment coordinates\n";
1345  throw OomphLibError(error_message.str(),
1346  OOMPH_CURRENT_FUNCTION,
1347  OOMPH_EXCEPTION_LOCATION);
1348  } // if (!found_original_segment)
1349 #endif
1350  } // for (is < nsegments)
1351 
1352  } // if (nsegments > 0)
1353 
1354  // -------------------------------------------------------------------
1355  // Fourth: The original mesh is different from the current mesh
1356  // (this). For boundaries with no geom object associated check if it
1357  // is required to reverse the zeta values. In order to reverse the
1358  // zeta values it is required to previously compute the arclength of
1359  // the segments and store the nodes in a container (set). NOTE that
1360  // the setup_boundary_coordinate() method is not called for
1361  // boundaries with NO GeomObject associated, so this is the LAST
1362  // CHANCE to do it
1363  // -------------------------------------------------------------------
1364  // The original mesh is the same as the current mesh (this). The
1365  // setup_boundary_method() will be called only for the boundaries
1366  // with NO GeomObject associated
1367  // -------------------------------------------------------------------
1368  if (this != original_mesh_pt)
1369  {
1370  // Get the boundary arclength
1371 
1372  // Get the initial and final zeta values for the boundary
1373  // (arclength) from the original mesh
1374  Vector<double> first_node_zeta_coordinate =
1375  original_mesh_pt->boundary_initial_zeta_coordinate(b);
1376  Vector<double> last_node_zeta_coordinate =
1377  original_mesh_pt->boundary_final_zeta_coordinate(b);
1378 
1379  // The boundary arclength is the maximum of the initial and final
1380  // zeta coordinate
1381  const double boundary_arclength =
1382  std::max(first_node_zeta_coordinate[0],
1383  last_node_zeta_coordinate[0]);
1384 
1385  for (unsigned is = 0; is < nsegments; is++)
1386  {
1387  // Here check if need to invert the elements and the boundary
1388  // coordinates for the segments in a boundary with no GeomObject
1389  // associated
1390  if (boundary_geom_object_pt(b)==0)
1391  {
1392  // This case only applies for the initial and iterative mesh in
1393  // the adaptation process because the method
1394  // setup_boundary_coordinates() is called by the original mesh
1395  // for boundaries with no GeomObject associated
1396 
1397  // We are goind to check if it is necessary to invert the order
1398  // of the zeta values
1399 
1400  // Get the first and last node of the current segment and their
1401  // zeta values (arclength)
1402 
1403  // There is no need to check for nonhalo elements since the
1404  // container has only nonhalo face elements
1405 
1406  // Get access to the first element on the segment
1407  FiniteElement* first_ele_pt=segment_sorted_ele_pt[is].front();
1408 
1409  // Number of nodes
1410  const unsigned nnod = first_ele_pt->nnode();
1411 
1412  // Get the first node of the current segment
1413  Node *first_node_pt = first_ele_pt->node_pt(0);
1414  if (is_inverted[first_ele_pt])
1415  {
1416  first_node_pt = first_ele_pt->node_pt(nnod-1);
1417  }
1418 
1419  // Get access to the last element on the segment
1420  FiniteElement* last_ele_pt=segment_sorted_ele_pt[is].back();
1421 
1422  // Get the last node of the current segment
1423  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
1424  if (is_inverted[last_ele_pt])
1425  {
1426  last_node_pt = last_ele_pt->node_pt(0);
1427  }
1428 
1429  // Get the zeta coordinates for the first and last node
1430  Vector<double> current_segment_initial_arclen(1);
1431  Vector<double> current_segment_final_arclen(1);
1432  // Is the segment in the current mesh (this) inverted?
1433  if (!Boundary_segment_inverted[b][is]) // Not inverted
1434  {
1435  first_node_pt->
1436  get_coordinates_on_boundary(b, current_segment_initial_arclen);
1437  last_node_pt->
1438  get_coordinates_on_boundary(b, current_segment_final_arclen);
1439  }
1440  else // Inverted
1441  {
1442  first_node_pt->
1443  get_coordinates_on_boundary(b, current_segment_final_arclen);
1444  last_node_pt->
1445  get_coordinates_on_boundary(b, current_segment_initial_arclen);
1446  }
1447 
1448  // Once the zeta values have been obtained check if they are set
1449  // in increasing or decreasing order
1450 
1451  // Flag to state that the values in the segment are in increasing
1452  // order
1453  bool increasing_order = false;
1454 
1455  // If the initial zeta value is smaller than the final zeta
1456  // value then they are in increasing order
1457  if (current_segment_initial_arclen[0] <
1458  current_segment_final_arclen[0])
1459  {
1460  increasing_order = true;
1461  }
1462  // If the initial zeta value is greater than the initial zeta
1463  // value then they are in decreasing order
1464  else if (current_segment_initial_arclen[0] >
1465  current_segment_final_arclen[0])
1466  {
1467  increasing_order = false;
1468  }
1469 #ifdef PARANOID
1470  else
1471  {
1472  std::stringstream error_message;
1473  error_message
1474  << "It was not possible to identify if the zeta values on "
1475  << "boundary ("<<b<<")\nand segment ("<<is<<") should go in "
1476  << "increasing or decreasing order.\n--- New mesh ---\n"
1477  << "Current segment initial arclength: ("
1478  << current_segment_initial_arclen[0]<<")\n"
1479  << "First node coordinates: ("
1480  << first_node_pt->x(0) << ", " << first_node_pt->x(1) << ")\n"
1481  << "Current segment final arclength: ("
1482  << current_segment_final_arclen[0]<<")\n"
1483  << "Last node coordinates: ("
1484  << last_node_pt->x(0) << ", " << last_node_pt->x(1) << ")\n"
1485  << "Current segment arclength: ("
1486  << segment_arclength[is] <<")\n";
1487  throw OomphLibError(error_message.str(),
1488  OOMPH_CURRENT_FUNCTION,
1489  OOMPH_EXCEPTION_LOCATION);
1490  }
1491 #endif
1492 
1493  // Now get the original initial and final arclengths and check
1494  // if they are in increasing or decreasing order
1495  const unsigned prev_s =
1496  current_segment_to_original_segment_index[is];
1497  const double original_segment_initial_arclength =
1498  original_mesh_pt->boundary_segment_initial_arclength(b)[prev_s];
1499  const double original_segment_final_arclength =
1500  original_mesh_pt->boundary_segment_final_arclength(b)[prev_s];
1501 
1502  // Flag to check if the values go in increasing or decreasing
1503  // order in the original mesh segment
1504  bool original_increasing_order = false;
1505 
1506  // Now check if the arclengths on the original mesh go in
1507  // increase or decrease order, this is also used to choose the
1508  // starting value to map the values in the current segment
1509  double starting_arclength = 0.0;
1510  if (original_segment_final_arclength >
1511  original_segment_initial_arclength)
1512  {
1513  // ... in increasing order in the original mesh ...
1514  original_increasing_order = true;
1515  // Select the starting arclength
1516  starting_arclength = original_segment_initial_arclength;
1517  }
1518  else if (original_segment_final_arclength <
1519  original_segment_initial_arclength)
1520  {
1521  // ... in decreasing order in the original mesh ...
1522  original_increasing_order = false;
1523  // Select the starting arclength
1524  starting_arclength = original_segment_final_arclength;
1525  }
1526 #ifdef PARANOID
1527  else
1528  {
1529  std::stringstream error_message;
1530  error_message
1531  << "It was not possible to identify if the zeta values on "
1532  << "boundary ("<<b<<")\nand segment ("<<is<<") should go in "
1533  << "increasing or decreasing order.\n--- Original mesh ---\n"
1534  << "Original segment initial arclength: ("
1535  << original_segment_initial_arclength<<")\n"
1536  << "Original segment final arclength: ("
1537  << original_segment_final_arclength<<")\n";
1538  throw OomphLibError(error_message.str(),
1539  OOMPH_CURRENT_FUNCTION,
1540  OOMPH_EXCEPTION_LOCATION);
1541  }
1542 #endif
1543 
1544  // Now scale the zeta values based considering if the zeta
1545  // values from the current mesh (this) go in the same order as
1546  // in the original mesh
1547  if (increasing_order && original_increasing_order)
1548  {
1549  // Current seg
1550  // |------|
1551  // 0 ---- 1
1552  //
1553  // Is mapped to the new values
1554  // |------|
1555  // a ---- b
1556  // a = original_segment_initial_arclength
1557  // b = original_segment_final_arclength
1558  // s = starting_arclength
1559  // The mapping is given by
1560  // new_z = s + z_old * (b - a)
1561 
1562  // Get the nodes associated to the segment
1563  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1564  // Go through all the nodes in the segment an change their
1565  // zeta values
1566  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1567  it != seg_nodes_pt.end(); it++)
1568  {
1569  // Storing for the zeta value
1570  Vector<double> zeta(1);
1571  // Get each node
1572  Node* nod_pt = (*it);
1573  // Get the zeta value of the current node
1574  nod_pt->get_coordinates_on_boundary(b, zeta);
1575  // ... and re-assign it
1576  const double temp =
1577  starting_arclength + (zeta[0] * segment_arclength[is]);
1578  // The zeta value
1579  zeta[0] = temp / boundary_arclength;
1580  // Correct
1581  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1582  {
1583  zeta[0] = 1.0;
1584  }
1585  else if (std::fabs(zeta[0]) < 1.0e-14)
1586  {
1587  zeta[0] = 0.0;
1588  }
1589 
1590  // Set the new value
1591  nod_pt->set_coordinates_on_boundary(b, zeta);
1592  } // Go through all the nodes
1593  } // if (increasing_order && original_increasing_order)
1594  else if (!increasing_order && original_increasing_order)
1595  {
1596  // Current seg
1597  // |------|
1598  // 1 ---- 0
1599  //
1600  // Is mapped to the new values
1601  // |------|
1602  // a ---- b
1603  // a = original_segment_initial_arclength
1604  // b = original_segment_final_arclength
1605  // s = starting_arclength
1606  // The mapping is given by
1607  // new_z = s + (1.0 - z_old) * (b - a)
1608 
1609  // Get the nodes associated to the segment
1610  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1611  // Go through all the nodes in the segment an change their
1612  // zeta values
1613  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1614  it != seg_nodes_pt.end(); it++)
1615  {
1616  // Storing for the zeta value
1617  Vector<double> zeta(1);
1618  // Get each node
1619  Node* nod_pt = (*it);
1620  // Get the zeta value of the current node
1621  nod_pt->get_coordinates_on_boundary(b, zeta);
1622  // ... and re-assign it
1623  const double temp =
1624  starting_arclength + ((1.0 - zeta[0]) * segment_arclength[is]);
1625  // The zeta value
1626  zeta[0] = temp / boundary_arclength;
1627  // Correct
1628  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1629  {
1630  zeta[0] = 1.0;
1631  }
1632  else if (std::fabs(zeta[0]) < 1.0e-14)
1633  {
1634  zeta[0] = 0.0;
1635  }
1636  // Set the new value
1637  nod_pt->set_coordinates_on_boundary(b, zeta);
1638  } // Go through all the nodes
1639  } // else if (!increasing_order && original_increasing_order)
1640  else if (increasing_order && !original_increasing_order)
1641  {
1642  // Current seg
1643  // |------|
1644  // 0 ---- 1
1645  //
1646  // Is mapped to the new values
1647  // |------|
1648  // b ---- a
1649  // a = original_segment_initial_arclength
1650  // b = original_segment_final_arclength
1651  // s = starting_arclength
1652  // The mapping is given by
1653  // new_z = s + (1.0 - z_old) * |(b - a)|
1654 
1655  // Get the nodes associated to the segment
1656  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1657  // Go through all the nodes in the segment an change their
1658  // zeta values
1659  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1660  it != seg_nodes_pt.end(); it++)
1661  {
1662  // Storing for the zeta value
1663  Vector<double> zeta(1);
1664  // Get each node
1665  Node* nod_pt = (*it);
1666  // Get the zeta value of the current node
1667  nod_pt->get_coordinates_on_boundary(b, zeta);
1668  // ... and re-assign it
1669  const double temp =
1670  starting_arclength + ((1.0 - zeta[0]) * segment_arclength[is]);
1671  // The zeta value
1672  zeta[0] = temp / boundary_arclength;
1673  // Correct
1674  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1675  {
1676  zeta[0] = 1.0;
1677  }
1678  else if (std::fabs(zeta[0]) < 1.0e-14)
1679  {
1680  zeta[0] = 0.0;
1681  }
1682  // Set the new value
1683  nod_pt->set_coordinates_on_boundary(b, zeta);
1684  } // Go through all the nodes
1685  } // else if (increasing_order && !original_increasing_order)
1686  else if (!increasing_order && !original_increasing_order)
1687  {
1688  // Current seg
1689  // |------|
1690  // 0 ---- 1
1691  //
1692  // Is mapped to the new values
1693  // |------|
1694  // a ---- b
1695  // a = original_segment_initial_arclength
1696  // b = original_segment_final_arclength
1697  // s = starting_arclength
1698  // The mapping is given by
1699  // new_z = s + z_old * |(b - a)|
1700 
1701  // Get the nodes associated to the segment
1702  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1703  // Go through all the nodes in the segment an change their
1704  // zeta values
1705  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1706  it != seg_nodes_pt.end(); it++)
1707  {
1708  // Storing for the zeta value
1709  Vector<double> zeta(1);
1710  // Get each node
1711  Node* nod_pt = (*it);
1712  // Get the zeta value of the current node
1713  nod_pt->get_coordinates_on_boundary(b, zeta);
1714  // ... and re-assign it
1715  const double temp =
1716  starting_arclength + (zeta[0] * segment_arclength[is]);
1717  // The zeta value
1718  zeta[0] = temp / boundary_arclength;
1719  // Correct
1720  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1721  {
1722  zeta[0] = 1.0;
1723  }
1724  else if (std::fabs(zeta[0]) < 1.0e-14)
1725  {
1726  zeta[0] = 0.0;
1727  }
1728  // Set the new value
1729  nod_pt->set_coordinates_on_boundary(b, zeta);
1730  } // Go through all the nodes
1731  } // else if (!increasing_order && !original_increasing_order)
1732 
1733 #ifdef PARANOID
1734  // Verify that the z values of the first and last node are not
1735  // out of the range [0,1]
1736  for (std::list<FiniteElement*>::iterator it_list =
1737  segment_sorted_ele_pt[is].begin();
1738  it_list != segment_sorted_ele_pt[is].end();
1739  it_list++)
1740  {
1741  // Number of nodes in the segment
1742  const unsigned nnod = (*it_list)->nnode();
1743 
1744  // Get the first node of the current segment
1745  Node *first_node_pt = (*it_list)->node_pt(0);
1746  if(is_inverted[(*it_list)])
1747  {
1748  first_node_pt = (*it_list)->node_pt(nnod-1);
1749  }
1750 
1751  // Get the last node of the current segment
1752  Node *last_node_pt = (*it_list)->node_pt(nnod-1);
1753  if(is_inverted[(*it_list)])
1754  {
1755  last_node_pt = (*it_list)->node_pt(0);
1756  }
1757 
1758  // The z value for the first node
1759  Vector<double> zeta(1);
1760  first_node_pt->get_coordinates_on_boundary(b, zeta);
1761  if (zeta[0] < 0.0 || zeta[0] > 1.0)
1762  {
1763  std::ostringstream error_message;
1764  error_message
1765  <<"The boundary coordinate of the first node on boundary ("
1766  << b << ")\nand segment (" << is << ") is out of the "
1767  << "allowed values [0,1]\n"
1768  << "The node boundary coordinate: (" << zeta[0] << ")\n"
1769  << "The vertex coordinates are: ("
1770  << first_node_pt->x(0) << ", " << first_node_pt->x(1) << ")\n";
1771  throw OomphLibError(error_message.str(),
1772  OOMPH_CURRENT_FUNCTION,
1773  OOMPH_EXCEPTION_LOCATION);
1774  }
1775 
1776  // The z value for the last node
1777  last_node_pt->get_coordinates_on_boundary(b, zeta);
1778  if (zeta[0] < 0.0 || zeta[0] > 1.0)
1779  {
1780  std::ostringstream error_message;
1781  error_message
1782  <<"The boundary coordinate of the last node on boundary ("
1783  << b << ")\nand segment (" << is << ") is out of the "
1784  << "allowed values [0,1]\n"
1785  << "The node boundary coordinate: (" << zeta[0] << ")\n"
1786  << "The vertex coordinates are: ("
1787  << last_node_pt->x(0) << ", " << last_node_pt->x(1) << ")\n";
1788  throw OomphLibError(error_message.str(),
1789  OOMPH_CURRENT_FUNCTION,
1790  OOMPH_EXCEPTION_LOCATION);
1791  }
1792  }
1793 #endif // #ifdef PARANOID
1794 
1795  } // if (boundary_geom_object_pt(b)==0)
1796 
1797  } // for (is < nsegments)
1798 
1799  } // if (this != original_mesh_pt)
1800 
1801  // ------------------------------------------------------------------
1802  // Copy the corrected (possible reversed) info. to the containers of
1803  // the current mesh
1804  // ------------------------------------------------------------------
1805  // Check if there are segments of b boundary in this processor
1806  if (nsegments > 0)
1807  {
1808  // Copy the initial and final coordinates
1809  Boundary_initial_coordinate[b] =
1810  original_mesh_pt->boundary_initial_coordinate(b);
1811 
1812  Boundary_final_coordinate[b] =
1813  original_mesh_pt->boundary_final_coordinate(b);
1814 
1815  // The initial and final zeta coordinates (In case of a geometric
1816  // object those are the limits of the geom object)
1817  Boundary_initial_zeta_coordinate[b] =
1818  original_mesh_pt->boundary_initial_zeta_coordinate(b);
1819 
1820  Boundary_final_zeta_coordinate[b] =
1821  original_mesh_pt->boundary_final_zeta_coordinate(b);
1822 
1823  } // if (nsegments > 0)
1824 
1825  // Set the flag to indicate that the zeta values have been assigned
1826  // for the current boundary
1827  Assigned_segments_initial_zeta_values[b] = true;
1828 
1829  // Clean all the created face elements
1830  for (unsigned i = 0; i < nele; i++)
1831  {
1832  delete face_el_pt[i];
1833  face_el_pt[i] = 0;
1834  }
1835 
1836  }
1837 
1838  //======================================================================
1839  /// \short Compute the boundary segments connectivity for those
1840  /// boundaries that were splited during the distribution process
1841  /// and also the initial zeta values for each segment (the initial
1842  /// and final boundary nodes coordinates)
1843  //======================================================================
1844  template<class ELEMENT>
1847  const unsigned& b)
1848  {
1849  // ------------------------------------------------------------------
1850  // First: Get the face elements associated with the current boundary
1851  // ------------------------------------------------------------------
1852 
1853  // Get the communicator of the mesh
1854  OomphCommunicator* comm_pt = this->communicator_pt();
1855 
1856  // Get the number of processors
1857  const unsigned nproc = comm_pt->nproc();
1858  // Get the rank of the current processor
1859  const unsigned my_rank = comm_pt->my_rank();
1860 
1861  // Temporary storage for face elements
1862  Vector<FiniteElement*> all_face_ele_pt;
1863 
1864  // Flag to know whether we are working with an internal open curve
1865  // and then re-assign the initial and final zeta coordinates for
1866  // each segment (only used when the mesh is distributed)
1867  bool is_internal_boundary = false;
1868 
1869  // map to associate the face element to the bulk element, necessary
1870  // to attach halo face elements at both sides of each found segment
1871  std::map<FiniteElement*,FiniteElement*> face_to_bulk_element_pt;
1872 
1873  // Select the boundary face elements, using the criteria of highest
1874  // processor in charge and bottom-left element
1875  select_boundary_face_elements(all_face_ele_pt, b, is_internal_boundary,
1876  face_to_bulk_element_pt);
1877 
1878  // Get the number of face elements
1879  const unsigned n_all_face_ele = all_face_ele_pt.size();
1880 
1881  // ----------------------------------------------------------------
1882  // Second: Sort the face elements, only consider nonhalo elements
1883  // ----------------------------------------------------------------
1884 
1885  // A flag vector to mark those face elements that are considered as
1886  // halo in the current processor
1887  std::vector<bool> is_halo_face_element(n_all_face_ele, false);
1888 
1889  // Count the total number of non halo face elements
1890  unsigned nnon_halo_face_elements = 0;
1891 
1892  // Only mark the face elements as halo if the mesh is marked as
1893  // distributed
1894  for (unsigned ie = 0; ie < n_all_face_ele; ie++)
1895  {
1896  FiniteElement* face_ele_pt = all_face_ele_pt[ie];
1897  // Get the bulk element
1898  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_ele_pt];
1899  // Check if the bulk element is halo
1900  if (!tmp_bulk_ele_pt->is_halo())
1901  {
1902  // Set the flag for non halo element
1903  is_halo_face_element[ie] = false;
1904  // Increase the non halo elements counter
1905  nnon_halo_face_elements++;
1906  }
1907  else
1908  {
1909  // Mark the face element as halo
1910  is_halo_face_element[ie] = true;
1911  }
1912 
1913  } // for (ie < n_ele)
1914 
1915  // Get the total number of halo face elements
1916  const unsigned nhalo_face_element = n_all_face_ele - nnon_halo_face_elements;
1917 
1918  // The vector of list to store the "segments" that compound the
1919  // boundary (segments may appear only in a distributed mesh)
1920  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
1921 
1922  // Number of already sorted face elements (only nonhalo elements for
1923  // a distributed mesh)
1924  unsigned nsorted_face_elements = 0;
1925 
1926  // Keep track of who's done (this apply to nonhalo only, remember we
1927  // are only working with halo elements)
1928  std::map<FiniteElement*, bool> done_el;
1929 
1930  // Keep track of which element is inverted (in distributed mesh the
1931  // elements may be inverted with respect to the segment they belong)
1932  std::map<FiniteElement*, bool> is_inverted;
1933 
1934  // Iterate until all possible segments have been created
1935  while(nsorted_face_elements < nnon_halo_face_elements)
1936  {
1937  // The ordered list of face elements (in a distributed mesh a
1938  // collection of contiguous face elements define a segment)
1939  std::list<FiniteElement*> sorted_el_pt;
1940  sorted_el_pt.clear();
1941 
1942 #ifdef PARANOID
1943  // Select an initial element for the segment (the first not done
1944  // nonhalo element)
1945  bool found_initial_face_element = false;
1946 #endif
1947 
1948  FiniteElement* ele_face_pt = 0;
1949 
1950  unsigned iface = 0;
1951  for (iface = 0; iface < n_all_face_ele; iface++)
1952  {
1953  if (!is_halo_face_element[iface])
1954  {
1955  ele_face_pt = all_face_ele_pt[iface];
1956  // If not done then take it as initial face element
1957  if (!done_el[ele_face_pt])
1958  {
1959 #ifdef PARANOID
1960  found_initial_face_element = true;
1961 #endif
1962  nsorted_face_elements++;
1963  iface++; // The next element number
1964  sorted_el_pt.push_back(ele_face_pt);
1965  // Mark as done
1966  done_el[ele_face_pt] = true;
1967  break;
1968  }
1969  }
1970  } // for (iface < nele)
1971 
1972 #ifdef PARANOID
1973  if (!found_initial_face_element)
1974  {
1975  std::ostringstream error_message;
1976  error_message
1977  <<"Could not find an initial face element for the current segment\n";
1978  // << "----- Possible memory leak -----\n";
1979  throw OomphLibError(error_message.str(),
1980  OOMPH_CURRENT_FUNCTION,
1981  OOMPH_EXCEPTION_LOCATION);
1982  }
1983 #endif
1984 
1985  // Number of nodes
1986  const unsigned nnod = ele_face_pt->nnode();
1987 
1988  // Left and rightmost nodes (the left and right nodes of the
1989  // current face element)
1990  Node* left_node_pt = ele_face_pt->node_pt(0);
1991  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
1992 
1993  // Continue iterating if a new face element has been added to the
1994  // list
1995  bool face_element_added = false;
1996 
1997  // While a new face element has been added to the set of sorted
1998  // face elements then re-iterate
1999  do
2000  {
2001  // Start from the next face element since we have already added
2002  // the previous one as the initial face element (any previous
2003  // face element had to be added on previous iterations)
2004  for (unsigned iiface = iface; iiface < n_all_face_ele; iiface++)
2005  {
2006  // Re-start flag
2007  face_element_added = false;
2008 
2009  // Get the candidate element
2010  ele_face_pt = all_face_ele_pt[iiface];
2011 
2012  // Check that the candidate element has not been done and is
2013  // not a halo element
2014  if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
2015  {
2016  // Get the left and right nodes of the current element
2017  Node* local_left_node_pt = ele_face_pt->node_pt(0);
2018  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
2019 
2020  // New element fits at the left of segment and is not inverted
2021  if (left_node_pt == local_right_node_pt)
2022  {
2023  left_node_pt = local_left_node_pt;
2024  sorted_el_pt.push_front(ele_face_pt);
2025  is_inverted[ele_face_pt] = false;
2026  face_element_added = true;
2027  }
2028  // New element fits at the left of segment and is inverted
2029  else if (left_node_pt == local_left_node_pt)
2030  {
2031  left_node_pt = local_right_node_pt;
2032  sorted_el_pt.push_front(ele_face_pt);
2033  is_inverted[ele_face_pt] = true;
2034  face_element_added = true;
2035  }
2036  // New element fits on the right of segment and is not inverted
2037  else if (right_node_pt == local_left_node_pt)
2038  {
2039  right_node_pt = local_right_node_pt;
2040  sorted_el_pt.push_back(ele_face_pt);
2041  is_inverted[ele_face_pt] = false;
2042  face_element_added = true;
2043  }
2044  // New element fits on the right of segment and is inverted
2045  else if (right_node_pt == local_right_node_pt)
2046  {
2047  right_node_pt = local_left_node_pt;
2048  sorted_el_pt.push_back(ele_face_pt);
2049  is_inverted[ele_face_pt] = true;
2050  face_element_added = true;
2051  }
2052 
2053  if (face_element_added)
2054  {
2055  done_el[ele_face_pt] = true;
2056  nsorted_face_elements++;
2057  break;
2058  }
2059 
2060  } // if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
2061  } // for (iiface<nnon_halo_face_element)
2062  }while(face_element_added &&
2063  (nsorted_face_elements < nnon_halo_face_elements));
2064 
2065  // Store the created segment in the vector of segments
2066  segment_sorted_ele_pt.push_back(sorted_el_pt);
2067 
2068  } // while(nsorted_face_elements < nnon_halo_face_elements);
2069 
2070  // -----------------------------------------------------------------
2071  // Third: We have the face elements sorted (in segments), now assign
2072  // boundary coordinates to the nodes in the segments, this is the
2073  // LOCAL boundary coordinate and further communication is needed to
2074  // compute the GLOBAL boundary coordinates
2075  // -----------------------------------------------------------------
2076 
2077  // Vector of sets that stores the nodes of each segment based on a
2078  // lexicographically order starting from the bottom left node of
2079  // each segment
2080  Vector<std::set<Node*> > segment_all_nodes_pt;
2081 
2082  // The number of segments in this processor
2083  const unsigned nsegments = segment_sorted_ele_pt.size();
2084 // DEBP(nsegments);
2085 
2086 #ifdef PARANOID
2087  if (nnon_halo_face_elements > 0 && nsegments == 0)
2088  {
2089  std::ostringstream error_message;
2090  error_message
2091  << "The number of segments is zero, but the number of nonhalo\n"
2092  << "elements is: (" << nnon_halo_face_elements << ")\n";
2093  throw OomphLibError(error_message.str(),
2094  OOMPH_CURRENT_FUNCTION,
2095  OOMPH_EXCEPTION_LOCATION);
2096  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
2097 #endif
2098 
2099  // The arclength of each segment in the current processor
2100  Vector<double> segment_arclength(nsegments);
2101 
2102  // The number of vertices of each segment
2103  Vector<unsigned> nvertices_per_segment(nsegments);
2104 
2105  // The initial zeta for the segment
2106  Vector<double> initial_zeta_segment(nsegments);
2107 
2108  // The final zeta for the segment
2109  Vector<double> final_zeta_segment(nsegments);
2110 
2111  // Go through all the segments and compute its ARCLENGTH (if the
2112  // boundary has a GeomObject associated then assign the initial and
2113  // final zeta values for the segment)
2114  for (unsigned is = 0; is < nsegments; is++)
2115  {
2116 #ifdef PARANOID
2117  if (segment_sorted_ele_pt[is].size() == 0)
2118  {
2119  std::ostringstream error_message;
2120  error_message
2121  << "The (" << is << ")-th segment has no elements\n";
2122  throw OomphLibError(error_message.str(),
2123  OOMPH_CURRENT_FUNCTION,
2124  OOMPH_EXCEPTION_LOCATION);
2125  } // if (segment_sorted_ele_pt[is].size() == 0)
2126 #endif
2127 
2128  // Get access to the first element on the segment
2129  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
2130 
2131  // Number of nodes
2132  const unsigned nnod = first_ele_pt->nnode();
2133 
2134  // Get the first node of the current segment
2135  Node *first_node_pt = first_ele_pt->node_pt(0);
2136  if (is_inverted[first_ele_pt])
2137  {
2138  first_node_pt = first_ele_pt->node_pt(nnod-1);
2139  }
2140 
2141  // Coordinates of left node
2142  double x_left = first_node_pt->x(0);
2143  double y_left = first_node_pt->x(1);
2144 
2145  // Initialise boundary coordinate (local boundary coordinate for
2146  // boundaries with more than one segment)
2147  Vector<double> zeta(1, 0.0);
2148 
2149  // If we have associated a GeomObject then it is not necessary to
2150  // compute the arclength, only read the values from the nodes at
2151  // the edges and set the initial and final zeta segment values
2152  if (this->boundary_geom_object_pt(b)!=0)
2153  {
2154  // Get the initial node coordinate
2155  first_node_pt->get_coordinates_on_boundary(b, zeta);
2156  // Set the initial zeta segment value
2157  initial_zeta_segment[is] = zeta[0];
2158 
2159  // Get access to the last element on the segment
2160  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
2161 
2162  // Get the last node of the current segment
2163  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
2164  if (is_inverted[last_ele_pt])
2165  {
2166  last_node_pt = last_ele_pt->node_pt(0);
2167  }
2168 
2169  // Get the final node coordinate
2170  last_node_pt->get_coordinates_on_boundary(b, zeta);
2171  // Set the final zeta segment value
2172  final_zeta_segment[is] = zeta[0];
2173 
2174  }
2175 
2176  // Sort the nodes in the segment (lexicographically bottom left
2177  // node)
2178  std::set<Node*> local_nodes_pt;
2179  // Insert the first node
2180  local_nodes_pt.insert(first_node_pt);
2181 
2182  // Now loop over nodes in order and increase the ARCLENGTH
2183  for (std::list<FiniteElement*>::iterator it =
2184  segment_sorted_ele_pt[is].begin();
2185  it != segment_sorted_ele_pt[is].end(); it++)
2186  {
2187  // Get the pointer to the element
2188  FiniteElement* el_pt = (*it);
2189 
2190  // Start node and increment
2191  unsigned k_nod = 1;
2192  int nod_diff = 1;
2193  // Access nodes in reverse?
2194  if (is_inverted[el_pt])
2195  {
2196  k_nod = nnod - 2;
2197  nod_diff = -1;
2198  }
2199 
2200  // Loop over nodes in the face element
2201  for (unsigned j = 1; j < nnod; j++)
2202  {
2203  Node* nod_pt = el_pt->node_pt(k_nod);
2204  k_nod += nod_diff;
2205 
2206  // Coordinates of right node
2207  double x_right = nod_pt->x(0);
2208  double y_right = nod_pt->x(1);
2209 
2210  // Increment boundary coordinate (the arclength)
2211  zeta[0] += sqrt(
2212  (x_right - x_left) * (x_right - x_left) + (y_right - y_left)
2213  * (y_right - y_left));
2214 
2215  // When we have a GeomObject associated to the boundary we already
2216  // know the zeta values for the nodes, there is no need to compute
2217  // the arclength
2218 // if (this->boundary_geom_object_pt(b)==0)
2219 // {
2220 // // Set boundary coordinate
2221 // // nod_pt->set_coordinates_on_boundary(b, zeta);
2222 // }
2223 
2224  // Increment reference coordinate
2225  x_left = x_right;
2226  y_left = y_right;
2227 
2228  // Get lexicographically bottom left node but only
2229  // use vertex nodes as candidates
2230  local_nodes_pt.insert(nod_pt);
2231 
2232  } // for (j < nnod)
2233 
2234  } // iterator over the elements in the segment
2235 
2236  // Info. to be passed to other processors
2237  // The initial arclength for the segment that goes after this depends
2238  // on the current segment arclength
2239  segment_arclength[is] = zeta[0];
2240 
2241  // Info. to be passed to the other processors
2242  // The initial vertex number for the segment that goes after this
2243  // depends on the current segment vertices number
2244  nvertices_per_segment[is] = local_nodes_pt.size();
2245 
2246  // Add the nodes for the corresponding segment in the container
2247  segment_all_nodes_pt.push_back(local_nodes_pt);
2248 
2249  // The attaching of the halo elements at both sides of the segments is
2250  // performed only if segments connectivity needs to be computed
2251 
2252  } // for (is < nsegments)
2253 
2254  // Container to store the number of vertices before each segment,
2255  // initialise to zero in case we have a non distributed boundary
2256  Vector<unsigned> nvertices_before_segment(nsegments,0);
2257 
2258  // Store the initial arclength for each segment of boundary in the
2259  // current processor, initalise to zero in case we have a non
2260  // distributed boundary
2261  Vector<double> initial_segment_arclength(nsegments,0.0);
2262 
2263  // Info. to be passed to other processors
2264  // If the boundary is distributed we need to know which processors does
2265  // have the initial and final segments, this helps to get the first and
2266  // last nodes coordinates (info. used to scale the bound coordinates)
2267 
2268  // Processors with the initial and final segment
2269  unsigned proc_with_initial_seg = 0;
2270  unsigned proc_with_final_seg = 0;
2271 
2272  // ... and the index of those segments (only of interest in the
2273  // processors that have the initial and final segments)
2274  unsigned initial_segment = 0;
2275  unsigned final_segment = 0;
2276 
2277  // Each segment needs to know whether it has to be inverted or not
2278  // Store whether a segment needs to be inverted or not
2279  Vector<unsigned> segment_inverted(nsegments);
2280 
2281  // Before attaching the halo elements create a copy of the data
2282  // structure without halo elements
2283  Vector<std::list<FiniteElement*> > segment_sorted_nonhalo_ele_pt(nsegments);
2284  for (unsigned is = 0; is < nsegments; is++)
2285  {
2286  for (std::list<FiniteElement*>::iterator it_seg =
2287  segment_sorted_ele_pt[is].begin();
2288  it_seg != segment_sorted_ele_pt[is].end();
2289  it_seg++)
2290  {
2291  segment_sorted_nonhalo_ele_pt[is].push_back((*it_seg));
2292  }
2293 
2294  } // for (is < nsegments)
2295 
2296  // --------------------------------------------------------------
2297  // Attach the halo elements at both sides of the segments
2298  for (unsigned is = 0; is < nsegments; is++)
2299  {
2300  // Get access to the first element on the segment
2301  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
2302 
2303  // Number of nodes
2304  const unsigned nnod = first_ele_pt->nnode();
2305 
2306  // Get the first node of the current segment
2307  Node *first_node_pt = first_ele_pt->node_pt(0);
2308  if (is_inverted[first_ele_pt])
2309  {
2310  first_node_pt = first_ele_pt->node_pt(nnod-1);
2311  }
2312 
2313  // Get access to the last element on the segment
2314  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
2315 
2316  // Get the last node of the current segment
2317  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
2318  if (is_inverted[last_ele_pt])
2319  {
2320  last_node_pt = last_ele_pt->node_pt(0);
2321  }
2322 
2323  // -----------------------------------------------------------------
2324  // Fourth: Now attach the halo elements to the left and right side
2325  // of each segment
2326  // -----------------------------------------------------------------
2327  bool attached_left_halo = false;
2328  bool attached_right_halo = false;
2329  if (nhalo_face_element > 0)
2330  {
2331  for (unsigned iiface = 0; iiface < n_all_face_ele; iiface++)
2332  {
2333  // Get the candidate element
2334  FiniteElement* halo_face_ele_pt = all_face_ele_pt[iiface];
2335 
2336  // Check that the element is a halo face element, we do not check
2337  // if the element has been already done since the halo elements
2338  // may be connected to more than one segment (2 at most), to the
2339  // left and right of different segments
2340  //
2341  // Segment k Halo Segment r
2342  // |---|---|---| |xxx| |---|---|---|
2343  //
2344  // Segment k Halo Segment r
2345  // |---|---|---|xxx|---|---|---|
2346  //
2347  if (is_halo_face_element[iiface])
2348  {
2349  // Get its left and right nodes
2350  Node* left_node_pt = halo_face_ele_pt->node_pt(0);
2351  Node* right_node_pt = halo_face_ele_pt->node_pt(nnod-1);
2352  // The halo element fits to the left of segment
2353  if (!attached_left_halo && (first_node_pt == right_node_pt ||
2354  first_node_pt == left_node_pt))
2355  {
2356  // Add the halo element to the left of the segment
2357  segment_sorted_ele_pt[is].push_front(halo_face_ele_pt);
2358 
2359  // Once a halo face element has been added to the left
2360  // mark as found halo to the left
2361  attached_left_halo = true;
2362  }
2363  // The halo element fits to the right of the segment
2364  else if (!attached_right_halo && (last_node_pt == left_node_pt ||
2365  last_node_pt == right_node_pt))
2366  {
2367  // Add the halo element to the right of the segment
2368  segment_sorted_ele_pt[is].push_back(halo_face_ele_pt);
2369  // Once a halo face element has been added to the right
2370  // mark as found halo to the right
2371  attached_right_halo = true;
2372  }
2373  // If we have already found elements to left and right then
2374  // break the loop
2375  if (attached_left_halo && attached_right_halo)
2376  {break;}
2377 
2378  } // if (is_halo_face_element[iiface])
2379 
2380  } // for (iiface < nel)
2381 
2382  } // if (nhalo_face_element > 0)
2383 
2384  } // for (is < nsegments)
2385 
2386  // The segments now have local coordinates assigned and halo
2387  // elements attached to them. Store that info. in the corresponding
2388  // data structures and be ready to send that info. to a root
2389  // processor. The root processor will be in charge of computing the
2390  // boundary coordinates for each segment of the boundary.
2391 
2392  // For each segment store the following information
2393  // --------------------------------------------------------------------
2394  // Stores the "rank" of the processor to the left of each segment,
2395  // zero if there is no processor to the left which states that the
2396  // segment is the first one on the boundary
2397  Vector<unsigned> left_processor_plus_one(nsegments);
2398 
2399  // Stores the "rank" of the processor to the right of each segment,
2400  // zero if there is no processor to the right which states that the
2401  // segment is the last one on the boundary
2402  Vector<unsigned> right_processor_plus_one(nsegments);
2403 
2404  // The id. of the halo element to the left of the segment, note that
2405  // this info. is not necessary if there is no processor to the left
2406  // of the segment
2407  Vector<unsigned> left_halo_element(nsegments);
2408 
2409  // The id. of the halo element to the right of the segment, note that
2410  // this info. is not necessary if there is no processor to the right
2411  // of the segment
2412  Vector<unsigned> right_halo_element(nsegments);
2413 
2414  // The id. of the haloed element to the left of the segment, note that
2415  // this info. is not necessary if there is no processor to the left
2416  // of the segment
2417  Vector<unsigned> left_haloed_element(nsegments);
2418 
2419  // The id. of the haloed element to the right of the segment, note
2420  // that this info. is not necessary if there is no processor to the
2421  // right of the segment
2422  Vector<unsigned> right_haloed_element(nsegments);
2423 
2424  // Go through all the segments and get the info.
2425  for (unsigned is = 0; is < nsegments; is++)
2426  {
2427  // Get access to the left most face element on the segment
2428  FiniteElement* left_face_ele_pt=segment_sorted_ele_pt[is].front();
2429 
2430  // Get the corresponding bulk element and check whether it is a halo
2431  // element or not
2432  FiniteElement* tmp_left_bulk_ele_pt =
2433  face_to_bulk_element_pt[left_face_ele_pt];
2434 
2435  // Check if the bulk element is halo
2436  if (tmp_left_bulk_ele_pt->is_halo())
2437  {
2438  // Then store the corresponding info.
2439  int left_proc = tmp_left_bulk_ele_pt->non_halo_proc_ID();
2440 #ifdef PARANOID
2441  if (left_proc < 0)
2442  {
2443  std::ostringstream error_message;
2444  error_message
2445  << "The current bulk element (left) is marked as halo but "
2446  << "the processor holding\nthe non-halo counterpart is "
2447  << "negative!\n";
2448  throw OomphLibError(error_message.str(),
2449  OOMPH_CURRENT_FUNCTION,
2450  OOMPH_EXCEPTION_LOCATION);
2451  }
2452 #endif
2453  // The processor "rank" to the left
2454  unsigned left_processor = static_cast<unsigned>(left_proc);
2455  left_processor_plus_one[is] = left_processor + 1;
2456 
2457  // Now get the id of the halo element to the left
2458  GeneralisedElement *left_element_pt = tmp_left_bulk_ele_pt;
2459 
2460  // Get the halo elements with left processor
2461  Vector<GeneralisedElement*> left_halo_element_pt =
2462  this->halo_element_pt(left_processor);
2463 
2464 #ifdef PARANOID
2465  // Flag to state that the halo element was found
2466  bool left_halo_element_found = false;
2467 #endif
2468 
2469  const unsigned n_halo_left = left_halo_element_pt.size();
2470  for (unsigned lh = 0; lh < n_halo_left; lh++)
2471  {
2472  if (left_element_pt == left_halo_element_pt[lh])
2473  {
2474  left_halo_element[is] = lh;
2475 #ifdef PARANOID
2476  left_halo_element_found = true;
2477 #endif
2478  break;
2479  }
2480  } // for (lh < n_halo_left)
2481 
2482 #ifdef PARANOID
2483  if (!left_halo_element_found)
2484  {
2485  std::ostringstream error_message;
2486  error_message
2487  << "The current bulk element (left) marked as halo was "
2488  << "not found in the vector of halo\nelements associated "
2489  << "with the (" << left_processor << ") processor.\n\n";
2490  throw OomphLibError(error_message.str(),
2491  OOMPH_CURRENT_FUNCTION,
2492  OOMPH_EXCEPTION_LOCATION);
2493  } // if (!left_halo_element_found)
2494 #endif
2495 
2496  // Get the left-most nonhalo element (use the backup list of
2497  // nonhalo elements)
2498  left_face_ele_pt = segment_sorted_nonhalo_ele_pt[is].front();
2499 
2500  // Get the corresponding bulk element
2501  tmp_left_bulk_ele_pt = face_to_bulk_element_pt[left_face_ele_pt];
2502 
2503 #ifdef PARANOID
2504  // This element should not be marked as halo
2505  if (tmp_left_bulk_ele_pt->is_halo())
2506  {
2507  std::ostringstream error_message;
2508  error_message
2509  << "The bulk element represetation of the left-most nonhalo face\n"
2510  << "element of the current segment ("<<is<<") is marked as halo,\n"
2511  << "but the face element created from it is nonhalo\n";
2512  throw OomphLibError(error_message.str(),
2513  OOMPH_CURRENT_FUNCTION,
2514  OOMPH_EXCEPTION_LOCATION);
2515  } // if (tmp_left_bulk_ele_pt->is_halo())
2516 #endif
2517 
2518  // Cast from "FiniteElement*" to "GeneralisedElement*" to be able
2519  // to search in the haloed vector
2520  left_element_pt = tmp_left_bulk_ele_pt;
2521 
2522 #ifdef PARANOID
2523  // Flag to state that the haloed element was found
2524  bool left_haloed_element_found = false;
2525 #endif
2526 
2527  // Now get the id for the haloed element to the left, get the
2528  // haloed elements from the processor to the left
2529  Vector<GeneralisedElement*> left_haloed_element_pt =
2530  this->haloed_element_pt(left_processor);
2531 
2532  const unsigned nhaloed_left = left_haloed_element_pt.size();
2533  for (unsigned lhd = 0; lhd < nhaloed_left; lhd++)
2534  {
2535  if (left_element_pt == left_haloed_element_pt[lhd])
2536  {
2537  left_haloed_element[is] = lhd;
2538 #ifdef PARANOID
2539  left_haloed_element_found = true;
2540 #endif
2541  break;
2542  }
2543  } // for (lhd < nhaloed_left)
2544 
2545 #ifdef PARANOID
2546  if (!left_haloed_element_found)
2547  {
2548  std::ostringstream error_message;
2549  error_message
2550  << "The current bulk element (left) marked as haloed was "
2551  << "not found in the vector of haloed\nelements associated "
2552  << "with processor ("<< left_processor << ").\n";
2553  throw OomphLibError(error_message.str(),
2554  OOMPH_CURRENT_FUNCTION,
2555  OOMPH_EXCEPTION_LOCATION);
2556  }
2557 #endif
2558  } // if (tmp_left_bulk_ele_pt->is_halo())
2559  else
2560  {
2561  // If not halo then state the info. to indicate that
2562  left_processor_plus_one[is] = 0;
2563  // Null this info.
2564  left_halo_element[is] = 0;
2565  // Null this info.
2566  left_haloed_element[is] = 0;
2567  }
2568 
2569  // Get access to the right most face element on the segment
2570  FiniteElement* right_face_ele_pt = segment_sorted_ele_pt[is].back();
2571 
2572  // Get the corresponding bulk element and check whether it is
2573  // a halo element or not
2574  FiniteElement* tmp_right_bulk_ele_pt =
2575  face_to_bulk_element_pt[right_face_ele_pt];
2576 
2577  // Check if the bulk element is halo
2578  if (tmp_right_bulk_ele_pt->is_halo())
2579  {
2580  // Then store the corresponding info.
2581  int right_proc = tmp_right_bulk_ele_pt->non_halo_proc_ID();
2582 #ifdef PARANOID
2583  if (right_proc < 0)
2584  {
2585  std::ostringstream error_message;
2586  error_message
2587  << "The current bulk element (right) is marked as halo but "
2588  << "the processor holding\nthe non-halo counterpart is "
2589  << "negative!\n";
2590  throw OomphLibError(error_message.str(),
2591  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
2592  OOMPH_EXCEPTION_LOCATION);
2593  }
2594 #endif
2595  // The processor "rank" to the right
2596  unsigned right_processor = static_cast<unsigned>(right_proc);
2597  right_processor_plus_one[is] = right_processor + 1;
2598 
2599  // Now get the id of the halo element to the right
2600  GeneralisedElement *right_element_pt = tmp_right_bulk_ele_pt;
2601 
2602  // Get the halo elements with right processor
2603  Vector<GeneralisedElement*> right_halo_element_pt =
2604  this->halo_element_pt(right_processor);
2605 
2606 #ifdef PARANOID
2607  // Flag to state that the halo element was found
2608  bool right_halo_element_found = false;
2609 #endif
2610 
2611  const unsigned nhalo_right = right_halo_element_pt.size();
2612  for (unsigned rh = 0; rh < nhalo_right; rh++)
2613  {
2614  if (right_element_pt == right_halo_element_pt[rh])
2615  {
2616  right_halo_element[is] = rh;
2617 #ifdef PARANOID
2618  right_halo_element_found = true;
2619 #endif
2620  break;
2621  }
2622  } // for (rh < nhalo_right)
2623 #ifdef PARANOID
2624  if (!right_halo_element_found)
2625  {
2626  std::ostringstream error_message;
2627  error_message
2628  << "The current bulk element (right) marked as halo was not "
2629  << "found in the vector of halo\nelements associated with "
2630  << "the (" << right_processor << ") processor.\n\n";
2631  throw OomphLibError(error_message.str(),
2632  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
2633  OOMPH_EXCEPTION_LOCATION);
2634  }
2635 #endif
2636 
2637  // Get the right-most nonhalo element (use the backup list of
2638  // nonhalo elements)
2639  right_face_ele_pt = segment_sorted_nonhalo_ele_pt[is].back();
2640 
2641  // Get the corresponding bulk element
2642  tmp_right_bulk_ele_pt=face_to_bulk_element_pt[right_face_ele_pt];
2643 #ifdef PARANOID
2644  // This element should not be marked as halo
2645  if (tmp_right_bulk_ele_pt->is_halo())
2646  {
2647  std::ostringstream error_message;
2648  error_message
2649  << "The bulk element represetation of the right-most nonhalo face\n"
2650  << "element of the current segment ("<<is<<") is marked as halo,\n"
2651  << "but the face element created from it is nonhalo\n";
2652  throw OomphLibError(error_message.str(),
2653  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
2654  OOMPH_EXCEPTION_LOCATION);
2655  } // if (tmp_right_bulk_ele_pt->is_halo())
2656 #endif
2657 
2658  // Cast from "FiniteElement*" to "GeneralisedElement*" to be able
2659  // to search in the haloed vector
2660  right_element_pt = tmp_right_bulk_ele_pt;
2661 
2662 #ifdef PARANOID
2663  // Flag to state that the haloed element was found
2664  bool right_haloed_element_found = false;
2665 #endif
2666 
2667  // Now get the id for the haloed element to the right
2668  Vector<GeneralisedElement*> right_haloed_element_pt =
2669  this->haloed_element_pt(right_processor);
2670 
2671  const unsigned nhaloed_right = right_haloed_element_pt.size();
2672  for (unsigned rhd = 0; rhd < nhaloed_right; rhd++)
2673  {
2674  if (right_element_pt == right_haloed_element_pt[rhd])
2675  {
2676  right_haloed_element[is] = rhd;
2677 #ifdef PARANOID
2678  right_haloed_element_found = true;
2679 #endif
2680  break;
2681  }
2682  } // for (rhd < nhaloed_right)
2683 
2684 #ifdef PARANOID
2685  if (!right_haloed_element_found)
2686  {
2687  std::ostringstream error_message;
2688  error_message
2689  << "The current bulk element (right) marked as haloed was not "
2690  << "found in the vector of haloed\nelements associated with "
2691  << "the ("<< right_processor << ") processor.\n\n";
2692  throw OomphLibError(error_message.str(),
2693  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
2694  OOMPH_EXCEPTION_LOCATION);
2695  }
2696 #endif
2697 
2698  } // if (tmp_right_bulk_ele_pt->is_halo())
2699  else
2700  {
2701  // If not halo then state the info. to indicate that
2702  right_processor_plus_one[is] = 0;
2703  // Null this info.
2704  right_halo_element[is] = 0;
2705  // Null this info.
2706  right_haloed_element[is] = 0;
2707  }
2708 
2709  } // for (is < nsegments). Used to get the halo info. of the
2710  // segments
2711 
2712  // Now we have all the info. to be sent to the root processor and
2713  // compute the correct (global) boundary coordinates for the current
2714  // boundary
2715 
2716  // The root processor will be in charge of performing the computing
2717  // of the coordinate values along the boundary, all the other
2718  // processors only send their info. and wait for receiving the new
2719  // starting values for each of its segments
2720 
2721  // Choose the root processor
2722  const unsigned root_processor = 0;
2723  // ------------------------------------------------------------------
2724  // Starts the MPI stage
2725 
2726  // The root processor receives the number of segments of each
2727  // processor associated to the current boundary
2728  Vector<unsigned> root_nsegments_per_processor(nproc);
2729  unsigned nsegments_mpi = nsegments;
2730  MPI_Gather(&nsegments_mpi, 1, MPI_UNSIGNED,
2731  &root_nsegments_per_processor[0], 1, MPI_UNSIGNED,
2732  root_processor, comm_pt->mpi_comm());
2733 
2734  // Package the info. and prepare it to be sent
2735  // For the packaged info. we send 7 data per each segment, the indexes
2736  // are as follow; 0 left proc, 1 right proc, 2 left halo, 3 right
2737  // halo, 4 left haloed, 5 right haloed and 6 for nvertices per
2738  // segment
2739  // The size of the package (unsigned)
2740  const unsigned spu = 7;
2741  Vector<unsigned> flat_packed_unsigned_send_data(nsegments*spu);
2742  for (unsigned is = 0; is < nsegments; is++)
2743  {
2744  flat_packed_unsigned_send_data[(spu*is)+0]=left_processor_plus_one[is];
2745  flat_packed_unsigned_send_data[(spu*is)+1]=right_processor_plus_one[is];
2746  flat_packed_unsigned_send_data[(spu*is)+2]=left_halo_element[is];
2747  flat_packed_unsigned_send_data[(spu*is)+3]=right_halo_element[is];
2748  flat_packed_unsigned_send_data[(spu*is)+4]=left_haloed_element[is];
2749  flat_packed_unsigned_send_data[(spu*is)+5]=right_haloed_element[is];
2750  flat_packed_unsigned_send_data[(spu*is)+6]=nvertices_per_segment[is];
2751  }
2752 
2753  // How many data will this processor send
2754  const unsigned nudata_to_send = flat_packed_unsigned_send_data.size();
2755 
2756  // How many data does the root processor will receive from each
2757  // processor
2758  Vector<int> root_nudata_to_receive(nproc,0);
2759  // Total number of data to receive from all processors
2760  unsigned root_nutotal_data_receive = 0;
2761  for (unsigned ip = 0; ip < nproc; ip++)
2762  {
2763  // Compute the number of data the root processor will receive from
2764  // each processor
2765  root_nudata_to_receive[ip] = root_nsegments_per_processor[ip] * spu;
2766  // Add on the total number of data to receive
2767  root_nutotal_data_receive+= root_nudata_to_receive[ip];
2768  }
2769 
2770  // Stores and compute the offsets (in root) for the data received
2771  // from each processor
2772  Vector<int> root_uoffsets_receive(nproc,0);
2773  root_uoffsets_receive[0] = 0;
2774  for (unsigned ip = 1; ip < nproc; ip++)
2775  {
2776  // Compute the offset to store the values from each processor
2777  root_uoffsets_receive[ip] =
2778  root_uoffsets_receive[ip-1] + root_nudata_to_receive[ip-1];
2779  }
2780 
2781  // Create at least one entry so we don't get a seg fault below
2782  if (flat_packed_unsigned_send_data.size()==0)
2783  {
2784  flat_packed_unsigned_send_data.resize(1);
2785  }
2786 
2787  // Vector where to receive the info.
2788  Vector<unsigned> flat_packed_unsigned_receive_data(
2789  root_nutotal_data_receive);
2790  if (my_rank!=root_processor)
2791  {
2792  // Create at least one entry so we don't get a seg fault below
2793  if (flat_packed_unsigned_receive_data.size()==0)
2794  {
2795  flat_packed_unsigned_receive_data.resize(1);
2796  }
2797  } // if (my_rank!=root_processor)
2798 
2799  MPI_Gatherv(&flat_packed_unsigned_send_data[0], // Flat package to
2800  // send info. from
2801  // each processor
2802  nudata_to_send, // Total number of data to send from
2803  // each processor
2804  MPI_UNSIGNED,
2805  &flat_packed_unsigned_receive_data[0], // Container
2806  // where to
2807  // receive the
2808  // info. from all
2809  // the processors
2810  &root_nudata_to_receive[0], // Number of data to receive
2811  // from each processor
2812  &root_uoffsets_receive[0], // The offset to store the
2813  // info. from each processor
2814  MPI_UNSIGNED,
2815  root_processor, //The processor that receives all the
2816  //info.
2817  comm_pt->mpi_comm());
2818 
2819  // Clear the flat package to send
2820  flat_packed_unsigned_send_data.clear();
2821  flat_packed_unsigned_send_data.resize(0);
2822 
2823  // Package the info. and prepare it to be sent
2824  // For the packaged info. we send 1 data per each segment which is
2825  // at the moment the arclength of each segment
2826  // The size of the package
2827  const unsigned spd = 1;
2828  Vector<double> flat_packed_double_send_data(nsegments*spd);
2829  for (unsigned is = 0; is < nsegments; is++)
2830  {
2831  flat_packed_double_send_data[(spd*is)+0]=segment_arclength[is];
2832  }
2833 
2834  // How many data will this processor send
2835  const unsigned nddata_to_send = flat_packed_double_send_data.size();
2836  // How many data does the root processor will receive from each
2837  // processor
2838  Vector<int> root_nddata_to_receive(nproc,0);
2839  // Total number of data to receive from all processors
2840  unsigned root_ndtotal_data_receive = 0;
2841  for (unsigned ip =0; ip < nproc; ip++)
2842  {
2843  root_nddata_to_receive[ip] = root_nsegments_per_processor[ip] * spd;
2844  root_ndtotal_data_receive+= root_nddata_to_receive[ip];
2845  }
2846 
2847  // Stores and compute the offsets for the data received from each
2848  // processor
2849  Vector<int> root_doffsets_receive(nproc,0);
2850  root_doffsets_receive[0] = 0;
2851  for (unsigned ip = 1; ip < nproc; ip++)
2852  {
2853  // Compute the offset to store the values from each processor
2854  root_doffsets_receive[ip] =
2855  root_doffsets_receive[ip-1] + root_nddata_to_receive[ip-1];
2856  }
2857 
2858  // Create at least one entry so we don't get a seg fault below
2859  if (flat_packed_double_send_data.size()==0)
2860  {
2861  flat_packed_double_send_data.resize(1);
2862  }
2863 
2864  // Vector where to receive the info.
2865  Vector<double> flat_packed_double_receive_data(root_ndtotal_data_receive);
2866  if (my_rank!=root_processor)
2867  {
2868  // Create at least one entry so we don't get a seg fault below
2869  if (flat_packed_double_receive_data.size()==0)
2870  {
2871  flat_packed_double_receive_data.resize(1);
2872  }
2873  }
2874 
2875  MPI_Gatherv(&flat_packed_double_send_data[0], // Flat package to
2876  // send info. from
2877  // each processor
2878  nddata_to_send, // Total number of data to send from
2879  // each processor
2880  MPI_DOUBLE,
2881  &flat_packed_double_receive_data[0], // Container where
2882  // to receive the
2883  // info. from all
2884  // the processors
2885  &root_nddata_to_receive[0], // Number of data to receive
2886  // from each processor
2887  &root_doffsets_receive[0], // The offset to store the
2888  // info. from each processor
2889  MPI_DOUBLE,
2890  root_processor, //The processor that receives all the
2891  //info.
2892  comm_pt->mpi_comm());
2893 
2894  // Clear the flat package to send
2895  flat_packed_double_send_data.clear();
2896  flat_packed_double_send_data.resize(0);
2897 
2898  // The next three containers are only used by the root processor at
2899  // the end of its computations but it is necessary that all the
2900  // processors know them when calling back the info.
2901 
2902  // Container that state the initial arclength for each segments
2903  // of each processor
2904  Vector<Vector<double> > root_initial_segment_arclength(nproc);
2905 
2906  // Container that state the number of vertices before each segment
2907  // in a given processor
2908  Vector<Vector<unsigned> > root_nvertices_before_segment(nproc);
2909 
2910  // The root processor needs to tell the other processor if it was
2911  // necessary to reverse a segment. Each processor should therefore
2912  // invert the face elements that compose every segment that was
2913  // inverted by the root processor
2914  Vector<Vector<unsigned> > root_segment_inverted(nproc);
2915 
2916  // Used to store the accumulated arclength, used at the end of
2917  // communications to store the total arclength
2918  double root_accumulated_arclength = 0.0;
2919 
2920  // Store the accumulated number of vertices, it means the total number
2921  // of vertices before each segment (counter)
2922  unsigned root_accumulated_vertices_before_segment = 0;
2923 
2924  // The root processor is in charge of performing the connections
2925  // of the segments that define the complete boundary
2926  if (my_rank == root_processor)
2927  {
2928  // From the flat packaged received data re-create the data
2929  // structures storing the info. regarding the connectivity of the
2930  // segments, the number of vertices per segment and the local
2931  // arclength of each segment
2932 
2933  // Stores the "rank" of the processor to the left of each segment,
2934  // zero if there is no processor to the left which states that the
2935  // segment is the first one on the boundary
2936  Vector<Vector<unsigned> > root_left_processor_plus_one(nproc);
2937 
2938  // Stores the "rank" of the processor to the right of each segment,
2939  // zero if there is no processor to the right which states that the
2940  // segment is the last one on the boundary
2941  Vector<Vector<unsigned> > root_right_processor_plus_one(nproc);
2942 
2943  // The id. of the halo element to the left of the segment, note that
2944  // this info. is not necessary if there is no processor to the left
2945  // of the segment or if the processor has no info about the boundary
2946  Vector<Vector<unsigned> > root_left_halo_element(nproc);
2947 
2948  // The id. of the halo element to the right of the segment, note
2949  // that this info. is not necessary if there is no processor to
2950  // the right of the segment or if the processor has no info about
2951  // the boundary
2952  Vector<Vector<unsigned> > root_right_halo_element(nproc);
2953 
2954  // The id. of the haloed element to the left of the segment, note
2955  // that this info. is not necessary if there is no processor to
2956  // the left of the segment or if the processor has no info about
2957  // the boundary
2958  Vector<Vector<unsigned> > root_left_haloed_element(nproc);
2959 
2960  // The id. of the haloed element to the right of the segment, note
2961  // that this info. is not necessary if there is no processor to the
2962  // right of the segment or if the processor has no info about the
2963  // boundary
2964  Vector<Vector<unsigned> > root_right_haloed_element(nproc);
2965 
2966  // The number of vertices per segment in each processor
2967  Vector<Vector<unsigned> > root_nvertices_per_segment(nproc);
2968 
2969  // The arclength of each of the segments in the processors
2970  Vector<Vector<double> > root_segment_arclength(nproc);
2971 
2972  unsigned ucounter = 0;
2973  unsigned dcounter = 0;
2974  for (unsigned ip = 0; ip < nproc; ip++)
2975  {
2976  // Get the number of segments in the current processor
2977  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
2978 
2979  root_left_processor_plus_one[ip].resize(nsegs_iproc);
2980  root_right_processor_plus_one[ip].resize(nsegs_iproc);
2981  root_left_halo_element[ip].resize(nsegs_iproc);
2982  root_right_halo_element[ip].resize(nsegs_iproc);
2983  root_left_haloed_element[ip].resize(nsegs_iproc);
2984  root_right_haloed_element[ip].resize(nsegs_iproc);
2985 
2986  // Additional info.
2987  root_nvertices_per_segment[ip].resize(nsegs_iproc);
2988  root_segment_arclength[ip].resize(nsegs_iproc);
2989  root_segment_inverted[ip].resize(nsegs_iproc);
2990 
2991  // Extract the info. from the BIG package received from all
2992  // processors
2993  for(unsigned is = 0; is < nsegs_iproc; is++)
2994  {
2995  // ------ The flat unsigned package ------
2996  root_left_processor_plus_one[ip][is] =
2997  flat_packed_unsigned_receive_data[ucounter++];
2998  root_right_processor_plus_one[ip][is] =
2999  flat_packed_unsigned_receive_data[ucounter++];
3000  root_left_halo_element[ip][is] =
3001  flat_packed_unsigned_receive_data[ucounter++];
3002  root_right_halo_element[ip][is] =
3003  flat_packed_unsigned_receive_data[ucounter++];
3004  root_left_haloed_element[ip][is] =
3005  flat_packed_unsigned_receive_data[ucounter++];
3006  root_right_haloed_element[ip][is] =
3007  flat_packed_unsigned_receive_data[ucounter++];
3008  root_nvertices_per_segment[ip][is] =
3009  flat_packed_unsigned_receive_data[ucounter++];
3010 
3011  // ------ The flat double package ------
3012  root_segment_arclength[ip][is] =
3013  flat_packed_double_receive_data[dcounter++];
3014  } // for (is < nsegs_iproc)
3015  } // for (ip < nproc)
3016 
3017  // Now the root processor has all the info. to find out the
3018  // CONNECTIVITY of the segments in each processor
3019 
3020  // Container that stores the info. related with the connectivity
3021  // of the segments of each processor
3022  Vector<Vector<int> > left_connected_segment_plus_one(nproc);
3023  Vector<Vector<int> > right_connected_segment_plus_one(nproc);
3024  for (unsigned ip = 0; ip < nproc; ip++)
3025  {
3026  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3027  left_connected_segment_plus_one[ip].resize(nsegs_iproc,-1);
3028  right_connected_segment_plus_one[ip].resize(nsegs_iproc,-1);
3029  } // for (ip < nprocs)
3030 
3031  // In charge of storing the connectivity of the segments, the pair
3032  // indicates the processor and the segment number
3033  std::list<std::pair<unsigned, unsigned> > proc_seg_connectivity;
3034  proc_seg_connectivity.clear();
3035 
3036  // Done segments on processor
3037  std::map<std::pair<unsigned, unsigned>, bool> done_segment;
3038 
3039  // Take the first segment of the first processor with segments and
3040  // add it to the list of segments
3041  unsigned left_proc = 0;
3042  unsigned right_proc = 0;
3043  unsigned left_seg = 0;
3044  unsigned right_seg = 0;
3045  for (unsigned ip = 0; ip < nproc; ip++)
3046  {
3047  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3048  if (nsegs_iproc > 0)
3049  {
3050  right_proc = left_proc = ip;
3051  right_seg = left_seg = 0;
3052  break; // Break because it is the first processor with at
3053  // least one segment
3054  }
3055  } // for (ip < nproc)
3056 
3057  // ... and add it to the list of segments
3058  std::pair<unsigned, unsigned> add_segment =
3059  std::make_pair(left_proc, left_seg);
3060  done_segment[add_segment] = true;
3061  proc_seg_connectivity.push_back(add_segment);
3062 
3063  // Flags to indicate when a segment was added to the left or right
3064  // of the current list of segments
3065  bool added_segment_to_the_left = false;
3066  bool added_segment_to_the_right = false;
3067 
3068  do // while(added_segment_to_the_left || added_segment_to_the_right)
3069  {
3070  // Read the left-most processor and segment in the list
3071  std::pair<unsigned, unsigned> left_pair =
3072  proc_seg_connectivity.front();
3073  left_proc = left_pair.first;
3074  left_seg = left_pair.second;
3075 
3076  // Get the processor number to the left of the left-most
3077  // segment in the list
3078  const unsigned new_left_proc =
3079  root_left_processor_plus_one[left_proc][left_seg];
3080 
3081  if (new_left_proc != 0)
3082  {
3083  // Initialise flag
3084  added_segment_to_the_left = false;
3085  // Get the left halo element id
3086  const unsigned left_halo_id =
3087  root_left_halo_element[left_proc][left_seg];
3088 
3089  // Get the left haloed element id
3090  const unsigned left_haloed_id =
3091  root_left_haloed_element[left_proc][left_seg];
3092 
3093  // Go through the segments on the new left processor and look
3094  // for the corresponding left_halo_id in the haloed_ids
3095  const unsigned nsegs_new_left_proc =
3096  root_nsegments_per_processor[new_left_proc-1];
3097 
3098  for (unsigned ils = 0; ils < nsegs_new_left_proc; ils++)
3099  {
3100  std::pair<unsigned, unsigned> candidate_seg =
3101  std::make_pair(new_left_proc-1, ils);
3102 
3103  // Check that the segment has not been already added
3104  if (!done_segment[candidate_seg])
3105  {
3106  // Only consider the segments on new left processor which
3107  // right processor is the current one (left_proc)
3108  const unsigned right_proc_of_new_left_proc =
3109  root_right_processor_plus_one[new_left_proc-1][ils];
3110  // Also get the left_proc_of_new_left_proc (in case that it
3111  // be necessary to invert the segment)
3112  const unsigned left_proc_of_new_left_proc =
3113  root_left_processor_plus_one[new_left_proc-1][ils];
3114  // Check the not inverted case (to the left and not
3115  // inverted)
3116  if (right_proc_of_new_left_proc != 0 &&
3117  right_proc_of_new_left_proc-1 == left_proc)
3118  {
3119  // Get the haloed/haloed element id of the current segment
3120  // in the new left processor and compare it to the
3121  // halo/haloed element id of the left_processor
3122  const unsigned right_halo_id =
3123  root_right_halo_element[new_left_proc-1][ils];
3124  const unsigned right_haloed_id =
3125  root_right_haloed_element[new_left_proc-1][ils];
3126  if (left_halo_id == right_haloed_id &&
3127  left_haloed_id == right_halo_id)
3128  {
3129  // We have a match of the segments (store the segment
3130  // number plus one on the processor to the left)
3131  left_connected_segment_plus_one[left_proc][left_seg]=
3132  ils+1;
3133  // Add the pair to the connectivity list
3134  proc_seg_connectivity.push_front(candidate_seg);
3135  added_segment_to_the_left = true;
3136  break;
3137  }
3138  } // if (right_proc_of_new_left_proc-1 == left_proc)
3139 
3140  // Check the inverted case (to the left and inverted)
3141  if (left_proc_of_new_left_proc != 0 &&
3142  left_proc_of_new_left_proc-1 == left_proc)
3143  {
3144  // Get the haloed element id of the current segment
3145  // (inverted version) in the new left processor and
3146  // compare it to the halo element id of the left_processor
3147  const unsigned inv_left_halo_id =
3148  root_left_halo_element[new_left_proc-1][ils];
3149  const unsigned inv_left_haloed_id =
3150  root_left_haloed_element[new_left_proc-1][ils];
3151  if (left_halo_id == inv_left_haloed_id &&
3152  left_haloed_id == inv_left_halo_id)
3153  {
3154  // We have a match of the segments (store the segment
3155  // number plus one on the processor to the left)
3156  left_connected_segment_plus_one[left_proc][left_seg]=
3157  ils+1;
3158  // Add the pair to the connectivity list
3159  proc_seg_connectivity.push_front(candidate_seg);
3160 
3161  // In addition to the connectivity we need to invert the
3162  // segment (the information)
3163  const unsigned tmp_proc =
3164  root_left_processor_plus_one[new_left_proc-1][ils];
3165  const unsigned tmp_halo =
3166  root_left_halo_element[new_left_proc-1][ils];
3167  const unsigned tmp_haloed =
3168  root_left_haloed_element[new_left_proc-1][ils];
3169 
3170  root_left_processor_plus_one[new_left_proc-1][ils] =
3171  root_right_processor_plus_one[new_left_proc-1][ils];
3172  root_left_halo_element[new_left_proc-1][ils] =
3173  root_right_halo_element[new_left_proc-1][ils];
3174  root_left_haloed_element[new_left_proc-1][ils] =
3175  root_right_haloed_element[new_left_proc-1][ils];
3176 
3177  root_right_processor_plus_one[new_left_proc-1][ils] =
3178  tmp_proc;
3179  root_right_halo_element[new_left_proc-1][ils]=tmp_halo;
3180  root_right_haloed_element[new_left_proc-1][ils] =
3181  tmp_haloed;
3182 
3183  // ... and mark the segment as inverted in the root
3184  // processor to inform back to the owner processor
3185  root_segment_inverted[new_left_proc-1][ils] = 1;
3186 
3187  added_segment_to_the_left = true;
3188  break;
3189  }
3190  } // if (left_proc_of_new_left_proc-1 == left_proc)
3191  } // if (!done_segment[candidate_segment])
3192  } // for (ils < nsegs_new_left_proc)
3193 
3194 #ifdef PARANOID
3195  if (!added_segment_to_the_left)
3196  {
3197  std::ostringstream error_message;
3198  error_message
3199  << "The corresponding processor and segment to the left of "
3200  << "the current left\nmost segment was not found\n";
3201  throw OomphLibError(error_message.str(),
3202  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3203  OOMPH_EXCEPTION_LOCATION);
3204  }
3205 #endif
3206  } // if (new_left_proc != 0)
3207  else
3208  {
3209  // No more segments to the left
3210  added_segment_to_the_left = false;
3211  }
3212 
3213  // Read the info. of the right processor and the right segment
3214  std::pair<unsigned, unsigned> right_pair =
3215  proc_seg_connectivity.back();
3216  right_proc = right_pair.first;
3217  right_seg = right_pair.second;
3218 
3219  // Get the processor number to the right of the right-most
3220  // segment in the list
3221  const unsigned new_right_proc =
3222  root_right_processor_plus_one[right_proc][right_seg];
3223 
3224  if (new_right_proc != 0)
3225  {
3226  // Initialise flag
3227  added_segment_to_the_right = false;
3228  // Get the right halo element id
3229  const unsigned right_halo_id =
3230  root_right_halo_element[right_proc][right_seg];
3231 
3232  // Get the right halo element id
3233  const unsigned right_haloed_id =
3234  root_right_haloed_element[right_proc][right_seg];
3235 
3236  // Go through the segments on the new right processor and look
3237  // for the corresponding right_halo_id in the haloed_ids
3238  const unsigned nsegs_new_right_proc =
3239  root_nsegments_per_processor[new_right_proc-1];
3240 
3241  for (unsigned irs = 0; irs < nsegs_new_right_proc; irs++)
3242  {
3243  std::pair<unsigned, unsigned> candidate_seg =
3244  std::make_pair(new_right_proc-1, irs);
3245 
3246  // Check that the segment has not been already added
3247  if (!done_segment[candidate_seg])
3248  {
3249  // Only consider the segments on new right processor which
3250  // left processor is the current one (right_proc)
3251  const unsigned left_proc_of_new_right_proc =
3252  root_left_processor_plus_one[new_right_proc-1][irs];
3253  // Also get the right_proc_of_new_right_proc (in case
3254  // that it be necessary to invert the segment)
3255  const unsigned right_proc_of_new_right_proc =
3256  root_right_processor_plus_one[new_right_proc-1][irs];
3257  // Check the not inverted case (to the right and not
3258  // inverted)
3259  if (left_proc_of_new_right_proc != 0 &&
3260  left_proc_of_new_right_proc-1 == right_proc)
3261  {
3262  // Get the haloed element id of the current segment in the
3263  // new right processor and compare it to the halo element
3264  // id of the right_processor
3265  const unsigned left_halo_id =
3266  root_left_halo_element[new_right_proc-1][irs];
3267  const unsigned left_haloed_id =
3268  root_left_haloed_element[new_right_proc-1][irs];
3269 
3270  if (right_halo_id == left_haloed_id &&
3271  right_haloed_id == left_halo_id)
3272  {
3273  // We have a match of the segments (store the segment
3274  // number plus one on the processor to the right)
3275  right_connected_segment_plus_one[right_proc][right_seg]=
3276  irs+1;
3277  // Add the connectivity information to the list
3278  proc_seg_connectivity.push_back(candidate_seg);
3279  added_segment_to_the_right = true;
3280  break;
3281  }
3282  } // if (left_proc_of_new_right_proc-1 == right_proc)
3283 
3284  // Check the inverted case (to the right and inverted)
3285  if (right_proc_of_new_right_proc != 0 &&
3286  right_proc_of_new_right_proc-1 == right_proc)
3287  {
3288  // Get the haloed element id of the current segment
3289  // (inverted version) in the new right processor and
3290  // compare it to the halo element id of the
3291  // right_processor
3292  const unsigned inv_right_halo_id =
3293  root_right_halo_element[new_right_proc-1][irs];
3294  const unsigned inv_right_haloed_id =
3295  root_right_haloed_element[new_right_proc-1][irs];
3296  if (right_halo_id == inv_right_haloed_id &&
3297  right_haloed_id == inv_right_halo_id)
3298  {
3299  // We have a match of the segments (store the segment
3300  // number plus one on the processor to the right)
3301  right_connected_segment_plus_one[right_proc][right_seg]=
3302  irs+1;
3303  // Add the connectivity information to the list
3304  proc_seg_connectivity.push_back(candidate_seg);
3305  // In addition to the connectivity we need to invert the
3306  // segment
3307  const unsigned tmp_proc =
3308  root_left_processor_plus_one[new_right_proc-1][irs];
3309  const unsigned tmp_halo =
3310  root_left_halo_element[new_right_proc-1][irs];
3311  const unsigned tmp_haloed =
3312  root_left_haloed_element[new_right_proc-1][irs];
3313 
3314  root_left_processor_plus_one[new_right_proc-1][irs] =
3315  root_right_processor_plus_one[new_right_proc-1][irs];
3316  root_left_halo_element[new_right_proc-1][irs] =
3317  root_right_halo_element[new_right_proc-1][irs];
3318  root_left_haloed_element[new_right_proc-1][irs] =
3319  root_right_haloed_element[new_right_proc-1][irs];
3320 
3321  root_right_processor_plus_one[new_right_proc-1][irs] =
3322  tmp_proc;
3323  root_right_halo_element[new_right_proc-1][irs]=tmp_halo;
3324  root_right_haloed_element[new_right_proc-1][irs] =
3325  tmp_haloed;
3326 
3327  // ... and mark the segment as inverted in the root
3328  // processor to inform back to the owner processor
3329  root_segment_inverted[new_right_proc-1][irs] = 1;
3330 
3331  added_segment_to_the_right = true;
3332  break;
3333  }
3334  } // if (right_proc_of_new_right_proc-1 == right_proc)
3335  } // if (!done_segment[candidate_segment])
3336  } // for (irs < nsegs_new_left_proc)
3337 
3338 #ifdef PARANOID
3339  if (!added_segment_to_the_right)
3340  {
3341  std::ostringstream error_message;
3342  error_message
3343  << "The corresponding processor and segment to the right of "
3344  << "the current right\nmost segment was not found\n";
3345  throw OomphLibError(error_message.str(),
3346  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3347  OOMPH_EXCEPTION_LOCATION);
3348  }
3349 #endif
3350  } // if (new_right_proc != 0)
3351  else
3352  {
3353  // No more segments to the left
3354  added_segment_to_the_right = false;
3355  }
3356 
3357  }while(added_segment_to_the_left || added_segment_to_the_right);
3358 
3359  // Once we have connected the segments then we can compute the
3360  // initial and final zeta values based on the arclength of each
3361  // individual segment
3362 
3363  // Get the total number of segments, which MUST be the same as the
3364  // total number of segments in all processors
3365  const unsigned ntotal_segments = proc_seg_connectivity.size();
3366 #ifdef PARANOID
3367  unsigned tmp_total_segments = 0;
3368  for (unsigned ip =0; ip < nproc; ip++)
3369  {
3370  tmp_total_segments+= root_nsegments_per_processor[ip];
3371  }
3372 
3373  // Check that the total number of segments in all processors is
3374  // the same as the number of segments that form the boundary
3375  if (ntotal_segments!=tmp_total_segments)
3376  {
3377  std::ostringstream error_message;
3378  error_message
3379  << "The number of sorted segments (" << ntotal_segments << ") on "
3380  << "boundary ("<< b <<")\nis different from the total number of "
3381  <<"segments ("<< tmp_total_segments <<") in all\nprocessors.\n\n";
3382  throw OomphLibError(error_message.str(),
3383  OOMPH_CURRENT_FUNCTION,
3384  OOMPH_EXCEPTION_LOCATION);
3385  } // if (ntotal_segments!=tmp_total_segments)
3386 #endif
3387 
3388  // Now that we know the connectivity of the segments we can
3389  // compute the initial arclength of each segment in the
3390  // processors. Additionally we also get the number of vertices
3391  // before each of the segments. Resize the containers considering
3392  // the number of segments in each processor
3393  for (unsigned ip = 0; ip < nproc; ip++)
3394  {
3395  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3396  root_initial_segment_arclength[ip].resize(nsegs_iproc);
3397  root_nvertices_before_segment[ip].resize(nsegs_iproc);
3398  }
3399 
3400  Vector<double> aux_initial_segment_arclength(ntotal_segments);
3401  Vector<unsigned> aux_nvertices_before_segment(ntotal_segments);
3402 
3403  ucounter = 0;
3404  for (std::list<std::pair<unsigned, unsigned> >::iterator
3405  it_list = proc_seg_connectivity.begin();
3406  it_list != proc_seg_connectivity.end(); it_list++)
3407  {
3408  const unsigned iproc = static_cast<unsigned>((*it_list).first);
3409  const unsigned iseg = static_cast<unsigned>((*it_list).second);
3410  const double iseg_arclength = root_segment_arclength[iproc][iseg];
3411  const unsigned iseg_nvertices = root_nvertices_per_segment[iproc][iseg];
3412 
3413  aux_initial_segment_arclength[ucounter] = root_accumulated_arclength;
3414  aux_nvertices_before_segment[ucounter] =
3415  root_accumulated_vertices_before_segment;
3416 
3417  // Set the initial zeta value for the segment
3418  root_initial_segment_arclength[iproc][iseg] = root_accumulated_arclength;
3419  // Set the number of vertices before the current segment
3420  root_nvertices_before_segment[iproc][iseg] =
3421  root_accumulated_vertices_before_segment;
3422 
3423  // Add the arclength of the segment to the global arclength
3424  root_accumulated_arclength+= iseg_arclength;
3425  // Add the number of vertices to the global number of vertices
3426  root_accumulated_vertices_before_segment+= iseg_nvertices - 1;
3427 
3428  // Increase the counter
3429  ucounter++;
3430  } // for (loop over the sorted segments to assigne initial
3431  // arlength and initial number of vertices)
3432 
3433  // Increase by one to get the total number of vertices on the
3434  // boundary
3435  root_accumulated_vertices_before_segment++;
3436 
3437  // Get the processors with the initial and final segment.
3438  proc_with_initial_seg = proc_seg_connectivity.front().first;
3439  proc_with_final_seg = proc_seg_connectivity.back().first;
3440  // Also get the corresponding initial and final segment indexes
3441  // (on the initial and final processors)
3442  initial_segment = proc_seg_connectivity.front().second;
3443  final_segment = proc_seg_connectivity.back().second;
3444 
3445  } // if (my_rank == root_processor)
3446 
3447  // Get the total number of segments
3448  unsigned root_ntotal_segments = 0;
3449  for (unsigned ip =0; ip < nproc; ip++)
3450  {
3451  root_ntotal_segments+= root_nsegments_per_processor[ip];
3452  }
3453 
3454  // Package the info. that will be sent to each processor. For the
3455  // unsigned package we send the number of vertices before each
3456  // segment in each processor and whether it was inverted or not
3457  // Package size
3458  const unsigned rspu = 2;
3459  flat_packed_unsigned_send_data.clear();
3460  flat_packed_unsigned_send_data.resize(root_ntotal_segments*rspu);
3461  unsigned ucounter = 0;
3462  // Collect the info. from all the segments in the processors
3463  for (unsigned ip = 0; ip < nproc; ip++)
3464  {
3465  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3466  for (unsigned is = 0; is < nsegs_iproc; is++)
3467  {
3468  flat_packed_unsigned_send_data[ucounter++] =
3469  root_nvertices_before_segment[ip][is];
3470  flat_packed_unsigned_send_data[ucounter++] =
3471  root_segment_inverted[ip][is];
3472  } // for (is < nsegs_iproc)
3473  } // for (ip < nproc)
3474 
3475  // How many data does the root processor will send to each processor
3476  Vector<int> root_nudata_to_send(nproc,0);
3477  for (unsigned ip =0; ip < nproc; ip++)
3478  {
3479  // Get the number of data to send to ip processor
3480  root_nudata_to_send[ip] = root_nsegments_per_processor[ip] * rspu;
3481  }
3482 
3483  // Store and compute the offsets for the data sent to each processor
3484  Vector<int> root_uoffsets_send(nproc,0);
3485  root_uoffsets_send[0] = 0;
3486  for (unsigned ip = 1; ip < nproc; ip++)
3487  {
3488  // Compute the offset to send the values to each processor
3489  root_uoffsets_send[ip] =
3490  root_uoffsets_send[ip-1] + root_nudata_to_send[ip-1];
3491  }
3492 
3493  // Number of data to receive from root
3494  unsigned nutotal_data_receive = nsegments * rspu;
3495 
3496  if (my_rank!=root_processor)
3497  {
3498  // Create at least one entry so we don't get a seg fault below
3499  if (flat_packed_unsigned_send_data.size()==0)
3500  {
3501  flat_packed_unsigned_send_data.resize(1);
3502  }
3503  }
3504 
3505  // Clear and resize the vector where to receive the info.
3506  flat_packed_unsigned_receive_data.clear();
3507  flat_packed_unsigned_receive_data.resize(nutotal_data_receive);
3508  // Create at least one entry so we don't get a seg fault below
3509  if (flat_packed_unsigned_receive_data.size()==0)
3510  {
3511  flat_packed_unsigned_receive_data.resize(1);
3512  }
3513 
3514  MPI_Scatterv(&flat_packed_unsigned_send_data[0],
3515  &root_nudata_to_send[0],
3516  &root_uoffsets_send[0],
3517  MPI_UNSIGNED,
3518  &flat_packed_unsigned_receive_data[0],
3519  nutotal_data_receive,
3520  MPI_UNSIGNED,
3521  root_processor,
3522  comm_pt->mpi_comm());
3523 
3524  // Package the info. that will be sent to each processor, for the
3525  // double package we send (one data per segment) the initial
3526  // arclength for each segment
3527  const unsigned rspd = 1;
3528  flat_packed_double_send_data.clear();
3529  flat_packed_double_send_data.resize(root_ntotal_segments*rspd);
3530  unsigned dcounter = 0;
3531  // Collect the info. from all the segments in the processors
3532  for (unsigned ip = 0; ip < nproc; ip++)
3533  {
3534  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3535  for (unsigned is = 0; is < nsegs_iproc; is++)
3536  {
3537  flat_packed_double_send_data[dcounter++] =
3538  root_initial_segment_arclength[ip][is];
3539  }
3540  }
3541 
3542  // How many data does the root processor will send to each processor
3543  Vector<int> root_nddata_to_send(nproc,0);
3544  for (unsigned ip =0; ip < nproc; ip++)
3545  {
3546  // Number of data send to ip processor
3547  root_nddata_to_send[ip] = root_nsegments_per_processor[ip] * rspd;
3548  }
3549 
3550  // Store and compute the offsets for the data sent to each processor
3551  Vector<int> root_doffsets_send(nproc,0);
3552  root_doffsets_send[0] = 0;
3553  for (unsigned ip = 1; ip < nproc; ip++)
3554  {
3555  // Compute the offset to send the values to each processor
3556  root_doffsets_send[ip] =
3557  root_doffsets_send[ip-1] + root_nddata_to_send[ip-1];
3558  }
3559 
3560  // Number of double data to receive from root
3561  unsigned ndtotal_data_receive = nsegments * rspd;
3562 
3563  if (my_rank!=root_processor)
3564  {
3565  // Create at least one entry so we don't get a seg fault below
3566  if (flat_packed_double_send_data.size()==0)
3567  {
3568  flat_packed_double_send_data.resize(1);
3569  }
3570  }
3571 
3572  // Clear and resize the vector where to receive the info.
3573  flat_packed_double_receive_data.clear();
3574  flat_packed_double_receive_data.resize(ndtotal_data_receive);
3575  // Create at least one entry so we don't get a seg fault below
3576  if (flat_packed_double_receive_data.size()==0)
3577  {
3578  flat_packed_double_receive_data.resize(1);
3579  }
3580 
3581  MPI_Scatterv(&flat_packed_double_send_data[0],
3582  &root_nddata_to_send[0],
3583  &root_doffsets_send[0],
3584  MPI_DOUBLE,
3585  &flat_packed_double_receive_data[0],
3586  ndtotal_data_receive,
3587  MPI_DOUBLE,
3588  root_processor,
3589  comm_pt->mpi_comm());
3590 
3591  // Read if the segments need to be inverted and read the initial
3592  // arclengths
3593  ucounter = 0;
3594  dcounter = 0;
3595 
3596  // Read the info. from the flat package and store it in their
3597  // corresponding containers
3598  for (unsigned is = 0; is < nsegments; is++)
3599  {
3600  // The flat unsigned package
3601  nvertices_before_segment[is] =
3602  flat_packed_unsigned_receive_data[ucounter++];
3603  // The segment inverted flag
3604  segment_inverted[is] = flat_packed_unsigned_receive_data[ucounter++];
3605  // The flat double package
3606  initial_segment_arclength[is] =
3607  flat_packed_double_receive_data[dcounter++];
3608  } // for (is < nsegments)
3609 
3610  // Perform two additional communications to get the total number of
3611  // vertices, the processors with the initial and final segments, the
3612  // corresponding initial and final segments ...
3613  const unsigned numore_info = 5;
3614  Vector<unsigned> flat_package_unsigned_more_info(numore_info);
3615  // Prepare the info ...
3616  flat_package_unsigned_more_info[0] = root_accumulated_vertices_before_segment;
3617  flat_package_unsigned_more_info[1] = proc_with_initial_seg;
3618  flat_package_unsigned_more_info[2] = proc_with_final_seg;
3619  flat_package_unsigned_more_info[3] = initial_segment;
3620  flat_package_unsigned_more_info[4] = final_segment;
3621 
3622  // Send the info. to all processors
3623  MPI_Bcast(&flat_package_unsigned_more_info[0], numore_info,
3624  MPI_UNSIGNED, root_processor, comm_pt->mpi_comm());
3625 
3626  // ... and store the info. in the proper containers
3627  root_accumulated_vertices_before_segment = flat_package_unsigned_more_info[0];
3628  proc_with_initial_seg = flat_package_unsigned_more_info[1];
3629  proc_with_final_seg = flat_package_unsigned_more_info[2];
3630  initial_segment = flat_package_unsigned_more_info[3];
3631  final_segment = flat_package_unsigned_more_info[4];
3632 
3633  // Do the same for the maximum zeta value
3634  MPI_Bcast(&root_accumulated_arclength, 1, MPI_DOUBLE,
3635  root_processor, comm_pt->mpi_comm());
3636 
3637  // -----------------------------------------------------------------
3638  // Clear the storage to store the data that will be used by the
3639  // setup boundary coordinates method, if we do not perform the
3640  // cleaning then previous data from previous iterations will remain
3641  // there
3642  // -----------------------------------------------------------------
3643  // The info. for the boundary
3644  Boundary_initial_coordinate[b].clear();
3645  Boundary_final_coordinate[b].clear();
3646 
3647  Boundary_initial_zeta_coordinate[b].clear();
3648  Boundary_final_zeta_coordinate[b].clear();
3649 
3650  // The info. for the segments
3651  Boundary_segment_inverted[b].clear();
3652  Boundary_segment_initial_coordinate[b].clear();
3653  Boundary_segment_final_coordinate[b].clear();
3654 
3655  Boundary_segment_initial_zeta[b].clear();
3656  Boundary_segment_final_zeta[b].clear();
3657 
3658  Boundary_segment_initial_arclength[b].clear();
3659  Boundary_segment_final_arclength[b].clear();
3660 
3661  // Now copy all the info. to the containers to be sent to any other
3662  // mesh (in the adaptation method)
3663  for (unsigned is = 0; is < nsegments; is++)
3664  {
3665  // At this point we can get the initial and final coordinates for
3666  // each segment
3667  Vector<double> first_seg_coord(2);
3668  Vector<double> last_seg_coord(2);
3669 
3670  // In order to get the first and last coordinates of each segment we
3671  // first need to identify the first and last nonhalo element of each
3672  // segment, and then get the first and last node of the segment
3673 
3674  // Get the first nonhalo face element on the segment
3675  FiniteElement* first_seg_ele_pt =
3676  segment_sorted_nonhalo_ele_pt[is].front();
3677 
3678 #ifdef PARANOID
3679  // Check if the face element is nonhalo, it shouldn't, but better
3680  // check
3681  if (first_seg_ele_pt->is_halo())
3682  {
3683  std::ostringstream error_message;
3684  error_message
3685  << "The first face element in the (" << is << ")-th segment is halo\n";
3686  throw OomphLibError(error_message.str(),
3687  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3688  OOMPH_EXCEPTION_LOCATION);
3689  } // if (tmp_first_bulk_ele_pt->is_halo())
3690 #endif
3691 
3692  // Number of nodes
3693  const unsigned nnod = first_seg_ele_pt->nnode();
3694 
3695  // Get the first node of the current segment
3696  Node *first_seg_node_pt = first_seg_ele_pt->node_pt(0);
3697  if (is_inverted[first_seg_ele_pt])
3698  {
3699  first_seg_node_pt = first_seg_ele_pt->node_pt(nnod-1);
3700  }
3701 
3702  // Get the last nonhalo face element on the segment
3703  FiniteElement* last_seg_ele_pt =
3704  segment_sorted_nonhalo_ele_pt[is].back();
3705 
3706 #ifdef PARANOID
3707  // Check if the face element is nonhalo, it shouldn't, but better
3708  // check
3709  if (last_seg_ele_pt->is_halo())
3710  {
3711  std::ostringstream error_message;
3712  error_message
3713  << "The last face element in the (" << is << ")-th segment is halo\n";
3714  throw OomphLibError(error_message.str(),
3715  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3716  OOMPH_EXCEPTION_LOCATION);
3717  } // if (tmp_first_bulk_ele_pt->is_halo())
3718 #endif
3719 
3720  // Get the last node of the current segment
3721  Node *last_seg_node_pt = last_seg_ele_pt->node_pt(nnod-1);
3722  if (is_inverted[last_seg_ele_pt])
3723  {
3724  last_seg_node_pt = last_seg_ele_pt->node_pt(0);
3725  }
3726 
3727  // Get the coordinates for the first and last segment's node
3728  for (unsigned i = 0; i < 2; i++)
3729  {
3730  first_seg_coord[i] = first_seg_node_pt->x(i);
3731  last_seg_coord[i] = last_seg_node_pt->x(i);
3732  }
3733 
3734  // -----------------------------------------------------------------
3735  // Copy the info. if the segment is inverted
3736  Boundary_segment_inverted[b].push_back(segment_inverted[is]);
3737 
3738  // Check if the segment is inverted, if that is the case then invert
3739  // the first and last seg. coordinates
3740  if (!segment_inverted[is])
3741  {
3742  // Store the initial and final coordinates that will help to
3743  // identify the segments in the new meshes created from this one
3744  Boundary_segment_initial_coordinate[b].push_back(first_seg_coord);
3745  Boundary_segment_final_coordinate[b].push_back(last_seg_coord);
3746  }
3747  else
3748  {
3749  // Store the initial and final coordinates that will help to
3750  // identify the segments in the new meshes created from this one
3751  // Invert the initial and final coordinates
3752  Boundary_segment_initial_coordinate[b].push_back(last_seg_coord);
3753  Boundary_segment_final_coordinate[b].push_back(first_seg_coord);
3754  }
3755 
3756  // Now assign initial and final zeta boundary coordinates for each
3757  // segment
3758  // -----------------------------------------------------------------
3759  // If there is a geom object then
3760  if (boundary_geom_object_pt(b)!=0)
3761  {
3762  // Store the initial and final zeta for the current segments (we
3763  // got this when we assigned arclength to the segments in the
3764  // current processor)
3765  if (segment_inverted[is])
3766  {
3767  Boundary_segment_initial_zeta[b].push_back(final_zeta_segment[is]);
3768  Boundary_segment_final_zeta[b].push_back(initial_zeta_segment[is]);
3769  }
3770  else
3771  {
3772  Boundary_segment_initial_zeta[b].push_back(initial_zeta_segment[is]);
3773  Boundary_segment_final_zeta[b].push_back(final_zeta_segment[is]);
3774  }
3775  } // if (boundary_geom_object_pt(b)!=0)
3776  else
3777  {
3778  // Store the initial arclength and vertices number for the
3779  // current segment
3780  Boundary_segment_initial_arclength[b].push_back(
3781  initial_segment_arclength[is]);
3782 
3783  Boundary_segment_final_arclength[b].push_back(
3784  initial_segment_arclength[is] + segment_arclength[is]);
3785 
3786  } // else if (boundary_geom_object_pt(b)!=0)
3787 
3788  } // // for (is < nsegments)
3789 
3790  // Get the number of segments from the sets of nodes
3791 #ifdef PARANOID
3792  if (segment_all_nodes_pt.size() != nsegments)
3793  {
3794  std::ostringstream error_message;
3795  error_message
3796  <<"The number of segments ("<<nsegments<<") and the number of "
3797  <<"set of nodes ("<<segment_all_nodes_pt.size()<<") representing\n"
3798  <<"the\nsegments is different!!!\n\n";
3799  throw OomphLibError(error_message.str(),
3800  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3801  OOMPH_EXCEPTION_LOCATION);
3802  }
3803 #endif
3804 
3805  // The nodes have been assigned arc-length coordinates from one end
3806  // or the other of the connected segment.
3807 
3808  // -----------------------------------------------------------------
3809  // If mesh is distributed get the info. regarding the initial and
3810  // final nodes coordinates on the boundary, same as the zeta
3811  // boundary values for those nodes
3812 
3813  // Storage for the coordinates of the first and last nodes on the
3814  // boundary
3815  Vector<double> first_coordinate(2);
3816  Vector<double> last_coordinate(2);
3817 
3818  // Storage for the zeta coordinate of the first and last nodes on
3819  // the boundary
3820  Vector<double> first_node_zeta_coordinate(1,0.0);
3821  Vector<double> last_node_zeta_coordinate(1,0.0);
3822 
3823  // Send three data to all processors, the x[0], x[1] coordinate and
3824  // the zeta coordinate
3825  const unsigned ndtotal_data = 3;
3826  Vector<double> flat_packed_double_data_initial_seg(ndtotal_data);
3827 
3828  // If the mesh is distributed then check if this processor has the
3829  // initial segment
3830  if (my_rank == proc_with_initial_seg)
3831  {
3832  // Stores the firts element of the segment
3833  FiniteElement* first_ele_pt = 0;
3834  // Stores the first node of the boundary
3835  Node *first_node_pt = 0;
3836  // Check if the segment is inverted
3837  if (!segment_inverted[initial_segment])
3838  {
3839  // Get access to the first element on the segment marked as
3840  // initial
3841  first_ele_pt = segment_sorted_ele_pt[initial_segment].front();
3842 
3843  // Number of nodes
3844  const unsigned nnod = first_ele_pt->nnode();
3845 
3846  // Get the first node of the current segment
3847  first_node_pt = first_ele_pt->node_pt(0);
3848  if (is_inverted[first_ele_pt])
3849  {
3850  first_node_pt = first_ele_pt->node_pt(nnod-1);
3851  }
3852  } // if (!segment_inverted[initial_segment])
3853  else
3854  {
3855  // Get access to the first element on the segment marked as
3856  // initial
3857  first_ele_pt = segment_sorted_ele_pt[initial_segment].back();
3858 
3859  // Number of nodes
3860  const unsigned nnod = first_ele_pt->nnode();
3861 
3862  // Get the first node of the current segment
3863  first_node_pt = first_ele_pt->node_pt(nnod-1);
3864  if (is_inverted[first_ele_pt])
3865  {
3866  first_node_pt = first_ele_pt->node_pt(0);
3867  }
3868  } // else if (!segment_inverted[initial_segment])
3869 
3870  // Get the coordinates for the first node
3871  for (unsigned i = 0; i < 2; i++)
3872  {
3873  flat_packed_double_data_initial_seg[i] = first_node_pt->x(i);
3874  }
3875 
3876  // Get the zeta coordinates for the first node
3877  Vector<double> tmp_zeta(1);
3878  first_node_pt->get_coordinates_on_boundary(b, tmp_zeta);
3879 
3880  // If there is a geometric object associated to the boundary then
3881  // further process is necessary
3882  if (this->boundary_geom_object_pt(b)!=0)
3883  {
3884  //tmp_zeta[0] = this->boundary_coordinate_limits(b)[0];
3885  }
3886  else
3887  {
3888  // Check if the initial boundary coordinate is different from
3889  // zero, if that is the case then we need to set it to zero
3890  if (tmp_zeta[0] >= 1.0e-14)
3891  {
3892  tmp_zeta[0]=0;
3893  }
3894  } // if (this->boundary_geom_object_pt(b)!=0)
3895 
3896  // Store the initial zeta value
3897  flat_packed_double_data_initial_seg[2] = tmp_zeta[0];
3898 
3899  } // if (my_rank == proc_with_initial_seg)
3900 
3901  // All processor receive the info. from the processor that has the
3902  // initial segment
3903  MPI_Bcast(&flat_packed_double_data_initial_seg[0], ndtotal_data,
3904  MPI_DOUBLE, proc_with_initial_seg, comm_pt->mpi_comm());
3905 
3906  // ... and all processor put that info. into the appropriate
3907  // storages
3908  for (unsigned i = 0; i < 2; i++)
3909  {
3910  first_coordinate[i] = flat_packed_double_data_initial_seg[i];
3911  }
3912  first_node_zeta_coordinate[0]=flat_packed_double_data_initial_seg[2];
3913 
3914  // -----------------------------------------------------------------
3915  // Send three data to all processors, the x[0], x[1] coordinate and
3916  // the zeta coordinate
3917  Vector<double> flat_packed_double_data_final_seg(ndtotal_data);
3918 
3919  // If the mesh is distributed then check if this processor has the
3920  // final segment
3921  if (my_rank == proc_with_final_seg)
3922  {
3923  // Get access to the last element on the segment
3924  FiniteElement* last_ele_pt = 0;
3925 
3926  // Get the last node of the current segment
3927  Node *last_node_pt = 0;
3928 
3929  // Check if the segment is inverted
3930  if (!segment_inverted[final_segment])
3931  {
3932  // Get access to the last element on the segment marked as
3933  // final
3934  last_ele_pt = segment_sorted_ele_pt[final_segment].back();
3935 
3936  // Number of nodes
3937  const unsigned nnod = last_ele_pt->nnode();
3938 
3939  // Get the last node of the current segment
3940  last_node_pt = last_ele_pt->node_pt(nnod-1);
3941  if (is_inverted[last_ele_pt])
3942  {
3943  last_node_pt = last_ele_pt->node_pt(0);
3944  }
3945  } // if (!segment_inverted[final_segment])
3946  else
3947  {
3948  // Get access to the first element on the segment marked as
3949  // initial
3950  last_ele_pt = segment_sorted_ele_pt[final_segment].front();
3951 
3952  // Number of nodes
3953  const unsigned nnod = last_ele_pt->nnode();
3954 
3955  // Get the first node of the current segment
3956  last_node_pt = last_ele_pt->node_pt(0);
3957  if (is_inverted[last_ele_pt])
3958  {
3959  last_node_pt = last_ele_pt->node_pt(nnod-1);
3960  }
3961  } // if (!segment_inverted[final_segment])
3962 
3963  // Get the coordinates for the last node
3964  for (unsigned i = 0; i < 2; i++)
3965  {
3966  flat_packed_double_data_final_seg[i]=last_node_pt->x(i);
3967  }
3968 
3969  // Get the zeta coordinates for the last node
3970  Vector<double> tmp_zeta(1);
3971  last_node_pt->get_coordinates_on_boundary(b, tmp_zeta);
3972 
3973  // If there is not a geometric object associated to the boundary
3974  // then further process is required
3975  if (this->boundary_geom_object_pt(b)!=0)
3976  {
3977  // Do nothing
3978  } // if (this->boundary_geom_object_pt(b)!=0)
3979  else
3980  {
3981  // Check if the final boundary coordinate is different from
3982  // the boundary arclength, if that is the case then we need
3983  // to set it to the accumulated arclength
3984  if (std::fabs(tmp_zeta[0] - root_accumulated_arclength) >= 1.0e-14)
3985  {
3986  tmp_zeta[0] = root_accumulated_arclength;
3987  }
3988  } // else if (this->boundary_geom_object_pt(b)!=0)
3989 
3990  // Store the final zeta value
3991  flat_packed_double_data_final_seg[2] = tmp_zeta[0];
3992 
3993  } // if (my_rank == proc_with_final_seg)
3994 
3995  // All processor receive the info. from the processor that has the
3996  // final segment
3997  MPI_Bcast(&flat_packed_double_data_final_seg[0], ndtotal_data,
3998  MPI_DOUBLE, proc_with_final_seg, comm_pt->mpi_comm());
3999 
4000  // All processor receive the info. from the processor that has the
4001  // final segment
4002  for (unsigned i = 0; i < 2; i++)
4003  {
4004  last_coordinate[i] = flat_packed_double_data_final_seg[i];
4005  }
4006  last_node_zeta_coordinate[0]=flat_packed_double_data_final_seg[2];
4007 
4008  // -----------------------------------------------------------------
4009  // Copy the values to the permanent storage
4010  Boundary_initial_coordinate[b] = first_coordinate;
4011  Boundary_final_coordinate[b] = last_coordinate;
4012 
4013  Boundary_initial_zeta_coordinate[b] = first_node_zeta_coordinate;
4014  Boundary_final_zeta_coordinate[b] = last_node_zeta_coordinate;
4015 
4016  // If we are dealing with an internal boundary then re-assign the
4017  // initial and final zeta values for the segments
4018  if (is_internal_boundary)
4019  {
4020  // Only re-assign zeta values if there are at least one nonhalo
4021  // segment, if all the possible segments are halo then the
4022  // synchronisation method will be in charge of assigning the
4023  // correct boundary coordinates
4024  if (nsegments > 0)
4025  {
4026  // Call the following method to re-construct the segments but
4027  // using only the nonhalo elements, therefore the boundary
4028  // coordinates need to be re-assigned
4029  re_assign_initial_zeta_values_for_internal_boundary(
4030  b, segment_sorted_nonhalo_ele_pt, is_inverted);
4031  }
4032 
4033  } // if (is_internal_boundary)
4034 
4035  // Now identify the boundary segments
4036  if (nsegments > 0)
4037  {
4038  // Identify the boundary segments in the current mesh
4039  //identify_boundary_segments_and_assign_initial_zeta_values(
4040  // b, all_face_ele_pt, is_internal_boundary, face_to_bulk_element_pt);
4041  identify_boundary_segments_and_assign_initial_zeta_values(b,this);
4042  } // if (nsegments > 0)
4043 
4044  // Clean all the created face elements
4045  for (unsigned i = 0; i < n_all_face_ele; i++)
4046  {
4047  delete all_face_ele_pt[i];
4048  all_face_ele_pt[i] = 0;
4049  }
4050 
4051  }
4052 
4053  //======================================================================
4054  /// \short Re-assign the boundary segments initial zeta (arclength)
4055  /// for those internal boundaries that were splited during the
4056  /// distribution process. Those boundaries that have one face element
4057  /// at each side of the boundary. Here we create the segments only
4058  /// with the nonhalo elements, therefore the boundary coordinates
4059  /// need to be re-assigned to be passed to the new meshes
4060  //======================================================================
4061  template<class ELEMENT>
4064  const unsigned& b,
4065  Vector<std::list<FiniteElement*> > &old_segment_sorted_ele_pt,
4066  std::map<FiniteElement*, bool> &old_is_inverted)
4067  {
4068  // ------------------------------------------------------------------
4069  // First: Get the face elements associated with the current boundary
4070  // Only include nonhalo face elements
4071  // ------------------------------------------------------------------
4072  // Temporary storage for face elements
4073  Vector<FiniteElement*> face_el_pt;
4074 
4075  // Temporary storage for the number of elements adjacent to the
4076  // boundary
4077  unsigned nele = 0;
4078 
4079  // Temporary storage for elements adjacent to the boundary that have
4080  // a common edge (related with internal boundaries)
4081  unsigned n_repeated_ele = 0;
4082 
4083  const unsigned n_regions = this->nregion();
4084 
4085  // Temporary storage for already done nodes
4086  Vector<std::pair<Node*, Node*> > done_nodes_pt;
4087 
4088  // If there is more than one region then only use boundary
4089  // coordinates from the bulk side (region 0)
4090  if (n_regions > 1)
4091  {
4092  for (unsigned rr = 0 ; rr < n_regions; rr++)
4093  {
4094  const unsigned region_id =
4095  static_cast<unsigned>(this->Region_attribute[rr]);
4096 
4097  // Loop over all elements on boundaries in region i_r
4098  const unsigned nel_in_region =
4099  this->nboundary_element_in_region(b, region_id);
4100 
4101  unsigned nel_repetead_in_region = 0;
4102 
4103  // Only bother to do anything else, if there are elements
4104  // associated with the boundary and the current region
4105  if (nel_in_region > 0)
4106  {
4107  bool repeated = false;
4108 
4109  // Loop over the bulk elements adjacent to boundary b
4110  for (unsigned e = 0; e < nel_in_region; e++)
4111  {
4112  // Get pointer to the bulk element that is adjacent to
4113  // boundary b
4114  FiniteElement* bulk_elem_pt =
4115  this->boundary_element_in_region_pt(b, region_id, e);
4116 
4117  // Remember only work with non halo elements
4118  if (bulk_elem_pt->is_halo())
4119  {
4120  n_repeated_ele++;
4121  continue;
4122  }
4123 
4124  // Find the index of the face of element e along boundary b
4125  int face_index =
4126  this->face_index_at_boundary_in_region(b,region_id,e);
4127 
4128  // Before adding the new element we need to be sure that the
4129  // edge that this element represent has not been already
4130  // added
4131  FiniteElement* tmp_ele_pt =
4132  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
4133 
4134  const unsigned n_nodes = tmp_ele_pt->nnode();
4135 
4136  std::pair<Node*, Node*> tmp_pair =
4137  std::make_pair(tmp_ele_pt->node_pt(0),
4138  tmp_ele_pt->node_pt(n_nodes - 1));
4139 
4140  std::pair<Node*, Node*> tmp_pair_inverse =
4141  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
4142  tmp_ele_pt->node_pt(0));
4143 
4144  // Search for repeated nodes
4145  const unsigned repeated_nodes_size = done_nodes_pt.size();
4146  for (unsigned l = 0; l < repeated_nodes_size; l++)
4147  {
4148  if (tmp_pair == done_nodes_pt[l] ||
4149  tmp_pair_inverse == done_nodes_pt[l])
4150  {
4151  nel_repetead_in_region++;
4152  repeated = true;
4153  break;
4154  }
4155  }
4156 
4157  // Create new face element
4158  if (!repeated)
4159  {
4160  // Add the pair of nodes (edge) to the node dones
4161  done_nodes_pt.push_back(tmp_pair);
4162  // Add the element to the face elements
4163  face_el_pt.push_back(tmp_ele_pt);
4164  }
4165  else
4166  {
4167  // Clean up
4168  delete tmp_ele_pt;
4169  tmp_ele_pt = 0;
4170  }
4171 
4172  // Re-start
4173  repeated = false;
4174 
4175  } // for nel
4176 
4177  nele += nel_in_region;
4178 
4179  n_repeated_ele += nel_repetead_in_region;
4180 
4181  } // if (nel_in_region > 0)
4182  } // for (rr < n_regions)
4183  } // if (n_regions > 1)
4184  //Otherwise it's just the normal boundary functions
4185  else
4186  {
4187  // Loop over all elements on boundaries
4188  nele = this->nboundary_element(b);
4189 
4190  //Only bother to do anything else, if there are elements
4191  if (nele > 0)
4192  {
4193  // Check for repeated ones
4194  bool repeated = false;
4195 
4196  // Loop over the bulk elements adjacent to boundary b
4197  for (unsigned e = 0; e < nele; e++)
4198  {
4199  // Get pointer to the bulk element that is adjacent to
4200  // boundary b
4201  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
4202 
4203  // Skip the halo elements, they are not included
4204  if (bulk_elem_pt->is_halo())
4205  {
4206  n_repeated_ele++;
4207  continue;
4208  }
4209 
4210  //Find the index of the face of element e along boundary b
4211  int face_index = this->face_index_at_boundary(b, e);
4212 
4213  // Before adding the new element we need to be sure that the
4214  // edge that this element represents has not been already
4215  // added (only applies for internal boundaries)
4216  FiniteElement* tmp_ele_pt =
4217  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
4218 
4219  const unsigned n_nodes = tmp_ele_pt->nnode();
4220 
4221  std::pair<Node*, Node*> tmp_pair =
4222  std::make_pair(tmp_ele_pt->node_pt(0),
4223  tmp_ele_pt->node_pt(n_nodes - 1));
4224 
4225  std::pair<Node*, Node*> tmp_pair_inverse =
4226  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
4227  tmp_ele_pt->node_pt(0));
4228 
4229  // Search for repeated nodes
4230  const unsigned repeated_nodes_size = done_nodes_pt.size();
4231  for (unsigned l = 0; l < repeated_nodes_size; l++)
4232  {
4233  if (tmp_pair == done_nodes_pt[l] ||
4234  tmp_pair_inverse == done_nodes_pt[l])
4235  {
4236  // Increase the number of repeated elements
4237  n_repeated_ele++;
4238  // Mark the element as repeated
4239  repeated = true;
4240  break;
4241  }
4242  }
4243 
4244  // Create new face element
4245  if (!repeated)
4246  {
4247  // Add the pair of nodes (edge) to the node dones
4248  done_nodes_pt.push_back(tmp_pair);
4249  // Add the element to the face elements
4250  face_el_pt.push_back(tmp_ele_pt);
4251  }
4252  else
4253  {
4254  // Free the repeated bulk element!!
4255  delete tmp_ele_pt;
4256  tmp_ele_pt = 0;
4257  }
4258 
4259  // Re-start
4260  repeated = false;
4261 
4262  } // for (e < nel)
4263  } // if (nel > 0)
4264 
4265  } // else (n_regions > 1)
4266 
4267  // Do not consider the repeated elements
4268  nele-= n_repeated_ele;
4269 
4270 #ifdef PARANOID
4271  if (nele!=face_el_pt.size())
4272  {
4273  std::ostringstream error_message;
4274  error_message
4275  << "The independet counting of face elements ("<<nele<<") for "
4276  << "boundary ("<<b<<") is different\n"
4277  << "from the real number of face elements in the container ("
4278  << face_el_pt.size() <<")\n";
4279  //<< "Possible memory leak\n"
4280  throw OomphLibError(error_message.str(),
4281  OOMPH_CURRENT_FUNCTION,
4282  OOMPH_EXCEPTION_LOCATION);
4283  }
4284 #endif
4285 
4286  // ----------------------------------------------------------------
4287  // Second: Sort the face elements, only consider nonhalo elements
4288  // ----------------------------------------------------------------
4289 
4290  // Get the total number of nonhalo face elements
4291  const unsigned nnon_halo_face_elements = face_el_pt.size();
4292 
4293  // The vector of list to store the "segments" that compound the
4294  // boundary (segments may appear only in a distributed mesh)
4295  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
4296 
4297  // Number of already sorted face elements
4298  unsigned nsorted_face_elements = 0;
4299 
4300  // Keep track of who's done
4301  std::map<FiniteElement*, bool> done_el;
4302 
4303  // Keep track of which element is inverted
4304  std::map<FiniteElement*, bool> is_inverted;
4305 
4306  // Iterate until all possible segments have been created
4307  while(nsorted_face_elements < nnon_halo_face_elements)
4308  {
4309  // The ordered list of face elements (in a distributed mesh a
4310  // collection of contiguous face elements define a segment)
4311  std::list<FiniteElement*> sorted_el_pt;
4312 
4313 #ifdef PARANOID
4314  // Select an initial element for the segment
4315  bool found_initial_face_element = false;
4316 #endif
4317 
4318  FiniteElement* ele_face_pt = 0;
4319 
4320  unsigned iface = 0;
4321  for (iface = 0; iface < nele; iface++)
4322  {
4323  ele_face_pt = face_el_pt[iface];
4324  // If not done then take it as initial face element
4325  if (!done_el[ele_face_pt])
4326  {
4327 #ifdef PARANOID
4328  // Mark as found the root face element
4329  found_initial_face_element = true;
4330 #endif
4331  // Increase the number of sorted face elements
4332  nsorted_face_elements++;
4333  // Increase the counter to mark the position of the next
4334  // element number
4335  iface++;
4336  // Add the face element in the list of sorted face elements
4337  sorted_el_pt.push_back(ele_face_pt);
4338  // Mark as done
4339  done_el[ele_face_pt] = true;
4340  break;
4341  } // if (!done_el[ele_face_pt])
4342  } // for (iface < nele)
4343 
4344 #ifdef PARANOID
4345  if (!found_initial_face_element)
4346  {
4347  std::ostringstream error_message;
4348  error_message
4349  <<"Could not find an initial face element for the current segment\n";
4350  throw OomphLibError(error_message.str(),
4351  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
4352  OOMPH_EXCEPTION_LOCATION);
4353  }
4354 #endif
4355 
4356  // Number of nodes
4357  const unsigned nnod = ele_face_pt->nnode();
4358 
4359  // Left and rightmost nodes (the left and right nodes of the
4360  // current face element)
4361  Node* left_node_pt = ele_face_pt->node_pt(0);
4362  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
4363 
4364  // Continue iterating if a new face element has been added to the
4365  // list
4366  bool face_element_added = false;
4367 
4368  // While a new face element has been added to the set of sorted
4369  // face elements then re-iterate
4370  do
4371  {
4372  // Start from the next face element since we have already added
4373  // the previous one as the initial face element (any previous
4374  // face element had to be added on previous iterations)
4375  for (unsigned iiface = iface; iiface < nele; iiface++)
4376  {
4377  // Re-start flag
4378  face_element_added = false;
4379 
4380  // Get the candidate element
4381  ele_face_pt = face_el_pt[iiface];
4382 
4383  // Check that the candidate element has not been done and is
4384  // not a halo element
4385  if (!(done_el[ele_face_pt]))
4386  {
4387  // Get the left and right nodes of the current element
4388  Node* local_left_node_pt = ele_face_pt->node_pt(0);
4389  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
4390 
4391  // New element fits at the left of segment and is not inverted
4392  if (left_node_pt == local_right_node_pt)
4393  {
4394  left_node_pt = local_left_node_pt;
4395  sorted_el_pt.push_front(ele_face_pt);
4396  is_inverted[ele_face_pt] = false;
4397  face_element_added = true;
4398  }
4399  // New element fits at the left of segment and is inverted
4400  else if (left_node_pt == local_left_node_pt)
4401  {
4402  left_node_pt = local_right_node_pt;
4403  sorted_el_pt.push_front(ele_face_pt);
4404  is_inverted[ele_face_pt] = true;
4405  face_element_added = true;
4406  }
4407  // New element fits on the right of segment and is not inverted
4408  else if (right_node_pt == local_left_node_pt)
4409  {
4410  right_node_pt = local_right_node_pt;
4411  sorted_el_pt.push_back(ele_face_pt);
4412  is_inverted[ele_face_pt] = false;
4413  face_element_added = true;
4414  }
4415  // New element fits on the right of segment and is inverted
4416  else if (right_node_pt == local_right_node_pt)
4417  {
4418  right_node_pt = local_left_node_pt;
4419  sorted_el_pt.push_back(ele_face_pt);
4420  is_inverted[ele_face_pt] = true;
4421  face_element_added = true;
4422  }
4423 
4424  if (face_element_added)
4425  {
4426  done_el[ele_face_pt] = true;
4427  nsorted_face_elements++;
4428  break;
4429  } // if (face_element_added)
4430 
4431  } // if (!(done_el[ele_face_pt]))
4432 
4433  } // for (iiface<nnon_halo_face_element)
4434 
4435  }while(face_element_added &&
4436  (nsorted_face_elements < nnon_halo_face_elements));
4437 
4438  // Store the created segment in the vector of segments
4439  segment_sorted_ele_pt.push_back(sorted_el_pt);
4440 
4441  } // while(nsorted_face_elements < nnon_halo_face_elements);
4442 
4443  // --------------------------------------------------------------
4444  // Third: We have the face elements sorted, now assign boundary
4445  // coordinates to the nodes in the segments and compute the
4446  // arclength of the segment.
4447  // --------------------------------------------------------------
4448 
4449  // The number of segments in this processor
4450  const unsigned nsegments = segment_sorted_ele_pt.size();
4451 
4452 #ifdef PARANOID
4453  if (nnon_halo_face_elements > 0 && nsegments == 0)
4454  {
4455  std::ostringstream error_message;
4456  error_message
4457  << "The number of segments is zero, but the number of nonhalo\n"
4458  << "elements is: (" << nnon_halo_face_elements << ")\n";
4459  throw OomphLibError(error_message.str(),
4460  OOMPH_CURRENT_FUNCTION,
4461  OOMPH_EXCEPTION_LOCATION);
4462  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
4463 #endif
4464 
4465  // Vector of sets that stores the nodes of each segment based on a
4466  // lexicographically order starting from the bottom left node of
4467  // each segment
4468  Vector<std::set<Node*> > segment_all_nodes_pt(nsegments);
4469 
4470  // Stores the nodes on each segment in the order they appear in the
4471  // face elements
4472  Vector<Vector<Node*> > sorted_segment_all_nodes_pt(nsegments);
4473 
4474  // Associate and arclength to each node on each segment of the
4475  // boundary, the nodes and therefore the arclength come in the same
4476  // order as the face elements
4477  Vector<Vector<double> > sorted_segment_node_arclength(nsegments);
4478 
4479  // The arclength of each segment in the current processor
4480  Vector<double> segment_arclength(nsegments);
4481 
4482  // The number of vertices of each segment
4483  Vector<unsigned> nvertices_per_segment(nsegments);
4484 
4485  // The initial zeta for the segment
4486  Vector<double> initial_zeta_segment(nsegments);
4487 
4488  // The final zeta for the segment
4489  Vector<double> final_zeta_segment(nsegments);
4490 
4491  // Go through all the segments and compute the LOCAL boundary
4492  // coordinates
4493  for (unsigned is = 0; is < nsegments; is++)
4494  {
4495 #ifdef PARANOID
4496  if (segment_sorted_ele_pt[is].size() == 0)
4497  {
4498  std::ostringstream error_message;
4499  error_message
4500  << "The (" << is << ")-th segment has no elements\n";
4501  throw OomphLibError(error_message.str(),
4502  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
4503  OOMPH_EXCEPTION_LOCATION);
4504  } // if (segment_sorted_ele_pt[is].size() == 0)
4505 #endif
4506 
4507  // Get access to the first element on the segment
4508  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
4509 
4510  // Number of nodes
4511  const unsigned nnod = first_ele_pt->nnode();
4512 
4513  // Get the first node of the current segment
4514  Node *first_node_pt = first_ele_pt->node_pt(0);
4515  if (is_inverted[first_ele_pt])
4516  {
4517  first_node_pt = first_ele_pt->node_pt(nnod-1);
4518  }
4519 
4520  // Coordinates of left node
4521  double x_left = first_node_pt->x(0);
4522  double y_left = first_node_pt->x(1);
4523 
4524  // Initialise boundary coordinate (local boundary coordinate for
4525  // boundaries with more than one segment)
4526  Vector<double> zeta(1, 0.0);
4527 
4528  // If we have associated a GeomObject then it is not necessary
4529  // to compute the arclength, only read the values from the nodes at
4530  // the edges
4531  if (this->boundary_geom_object_pt(b)!=0)
4532  {
4533  first_node_pt->get_coordinates_on_boundary(b, zeta);
4534  initial_zeta_segment[is] = zeta[0];
4535 
4536  // Get access to the last element on the segment
4537  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
4538 
4539  // Get the last node of the current segment
4540  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
4541  if (is_inverted[last_ele_pt])
4542  {
4543  last_node_pt = last_ele_pt->node_pt(0);
4544  }
4545 
4546  last_node_pt->get_coordinates_on_boundary(b, zeta);
4547  final_zeta_segment[is] = zeta[0];
4548  }
4549 
4550  // Sort the nodes in the segment (lexicographically bottom left
4551  // node)
4552  std::set<Node*> local_nodes_pt;
4553  local_nodes_pt.insert(first_node_pt);
4554 
4555  // Associate and arclength to the sorted nodes
4556  Vector<double> sorted_node_arclength;
4557  sorted_node_arclength.push_back(0.0);
4558 
4559  // Sorts the nodes in the segments according their sorting in the
4560  // face elements
4561  Vector<Node*> sorted_nodes_pt;
4562  sorted_nodes_pt.push_back(first_node_pt);
4563 
4564  // Now loop over nodes in order
4565  for (std::list<FiniteElement*>::iterator it =
4566  segment_sorted_ele_pt[is].begin();
4567  it != segment_sorted_ele_pt[is].end(); it++)
4568  {
4569  // Get the face element
4570  FiniteElement* el_pt = *it;
4571 
4572  // Start node and increment
4573  unsigned k_nod = 1;
4574  int nod_diff = 1;
4575  if (is_inverted[el_pt])
4576  {
4577  k_nod = nnod - 2;
4578  nod_diff = -1;
4579  }
4580 
4581  // Loop over nodes
4582  for (unsigned j = 1; j < nnod; j++)
4583  {
4584  Node* nod_pt = el_pt->node_pt(k_nod);
4585  k_nod += nod_diff;
4586 
4587  // Coordinates of right node
4588  double x_right = nod_pt->x(0);
4589  double y_right = nod_pt->x(1);
4590 
4591  // Increment boundary coordinate
4592  zeta[0] += sqrt(
4593  (x_right - x_left) * (x_right - x_left) + (y_right - y_left)
4594  * (y_right - y_left));
4595 
4596  // When we have a GeomObject associated to the boundary we already
4597  // know the zeta values for the nodes, there is no need to compute
4598  // the arclength
4599  if (this->boundary_geom_object_pt(b)==0)
4600  {
4601  // Set boundary coordinate
4602 // nod_pt->set_coordinates_on_boundary(b, zeta);
4603  }
4604 
4605  // Increment reference coordinate
4606  x_left = x_right;
4607  y_left = y_right;
4608 
4609  // Get lexicographically bottom left node but only
4610  // use vertex nodes as candidates
4611  local_nodes_pt.insert(nod_pt);
4612 
4613  // Associate the arclength for the current node
4614  sorted_node_arclength.push_back(zeta[0]);
4615 
4616  // Store the node in the sorted nodes storage
4617  sorted_nodes_pt.push_back(nod_pt);
4618 
4619  } // for (j < nnod)
4620 
4621  } // iterator over the elements in the segment
4622 
4623  // Info. to be passed to the other processors
4624  // The initial arclength for the segment that goes after this depends
4625  // on the current segment arclength
4626  segment_arclength[is] = zeta[0];
4627 
4628  // Info. to be passed to the other processors
4629  // The initial vertex number for the segment that goes after this
4630  // depends on the current sement vertices number
4631  nvertices_per_segment[is] = local_nodes_pt.size();
4632 
4633  // Add the nodes for the corresponding segment in the container
4634  segment_all_nodes_pt[is] = local_nodes_pt;
4635 
4636  // Add the arclengths to the nodes in the segment
4637  sorted_segment_node_arclength[is] = sorted_node_arclength;
4638 
4639  // Add the sorted nodes to the storage
4640  sorted_segment_all_nodes_pt[is] = sorted_nodes_pt;
4641 
4642  // The attaching of the halo elements at both sides of the segments is
4643  // performed only if segments connectivity needs to be computed
4644 
4645  } // for (is < nsegments)
4646 
4647  // ------------------------------------------------------------------
4648  // Fourth: Now we have the segments sorted, with arclength and with
4649  // LOCAL boundary coordinates assigned to the nodes. Identify the
4650  // nodes on the segments with the input segments and re-assign all
4651  // the info. related with the identification of segments
4652  // ------------------------------------------------------------------
4653 
4654  // Get the number of segments for the old sorted segments
4655  const unsigned old_nsegments = old_segment_sorted_ele_pt.size();
4656 
4657  // ------------------------------------------------------------------
4658  // Copy the old info. in temporary storages
4659  Vector<unsigned> old_boundary_segment_inverted(old_nsegments);
4660 
4662  old_boundary_segment_initial_coordinate(old_nsegments);
4664  old_boundary_segment_final_coordinate(old_nsegments);
4665 
4666  Vector<double> old_boundary_segment_initial_zeta(old_nsegments);
4667  Vector<double> old_boundary_segment_final_zeta(old_nsegments);
4668 
4669  Vector<double> old_boundary_segment_initial_arclength(old_nsegments);
4670  Vector<double> old_boundary_segment_final_arclength(old_nsegments);
4671 
4672  // Back-up the information
4673  for (unsigned old_is = 0; old_is < old_nsegments; old_is++)
4674  {
4675  old_boundary_segment_inverted[old_is] =
4676  boundary_segment_inverted(b)[old_is];
4677 
4678  old_boundary_segment_initial_coordinate[old_is].resize(2);
4679  old_boundary_segment_final_coordinate[old_is].resize(2);
4680  for (unsigned i = 0; i < 2; i++)
4681  {
4682  old_boundary_segment_initial_coordinate[old_is][i] =
4683  boundary_segment_initial_coordinate(b)[old_is][i];
4684 
4685  old_boundary_segment_final_coordinate[old_is][i] =
4686  boundary_segment_final_coordinate(b)[old_is][i];
4687  }
4688 
4689  // Check if the boundary has an associated GeomObject
4690  if (this->boundary_geom_object_pt(b)!=0)
4691  {
4692  old_boundary_segment_initial_zeta[old_is] =
4693  boundary_segment_initial_zeta(b)[old_is];
4694 
4695  old_boundary_segment_final_zeta[old_is] =
4696  boundary_segment_final_zeta(b)[old_is];
4697 
4698  } // if (this->boundary_geom_object_pt(b)!=0)
4699  else
4700  {
4701  old_boundary_segment_initial_arclength[old_is] =
4702  boundary_segment_initial_arclength(b)[old_is];
4703 
4704  old_boundary_segment_final_arclength[old_is] =
4705  boundary_segment_final_arclength(b)[old_is];
4706 
4707  } // else if (this->boundary_geom_object_pt(b)!=0)
4708 
4709  } // for (old_is < old_nsegments)
4710 
4711  // ------------------------------------------------------------------
4712  // Now clear the original storages
4713  Boundary_segment_inverted[b].clear();
4714  Boundary_segment_initial_coordinate[b].clear();
4715  Boundary_segment_final_coordinate[b].clear();
4716 
4717  Boundary_segment_initial_zeta[b].clear();
4718  Boundary_segment_final_zeta[b].clear();
4719 
4720  Boundary_segment_initial_arclength[b].clear();
4721  Boundary_segment_final_arclength[b].clear();
4722  // ------------------------------------------------------------------
4723  // .. and resize the storages for the new number of segments
4724  Boundary_segment_inverted[b].resize(nsegments);
4725  Boundary_segment_initial_coordinate[b].resize(nsegments);
4726  Boundary_segment_final_coordinate[b].resize(nsegments);
4727 
4728  // Check if the boundary has an associated GeomObject
4729  if (this->boundary_geom_object_pt(b)!=0)
4730  {
4731  Boundary_segment_initial_zeta[b].resize(nsegments);
4732  Boundary_segment_final_zeta[b].resize(nsegments);
4733  }
4734  else
4735  {
4736  Boundary_segment_initial_arclength[b].resize(nsegments);
4737  Boundary_segment_final_arclength[b].resize(nsegments);
4738  }
4739  // ------------------------------------------------------------------
4740  // map to know if the new segment has been re-assigned the info.
4741  std::map<unsigned, bool> done_segment;
4742 
4743  // Count the number of re-assigned segments with the new values
4744  unsigned re_assigned_segments = 0;
4745 
4746  // Go through all the old segments (the input segments)
4747  for (unsigned old_is = 0; old_is < old_nsegments; old_is++)
4748  {
4749  // Get the first and last zeta values for the current segment
4750  const double old_initial_arclength =
4751  old_boundary_segment_initial_arclength[old_is];
4752  const double old_final_arclength =
4753  old_boundary_segment_final_arclength[old_is];
4754  // Get the "is inverted" segment information
4755  const unsigned old_inverted_segment =
4756  old_boundary_segment_inverted[old_is];
4757 
4758  // Check if the boundary coordinates in the segment go in
4759  // increasing or decreasing order
4760  bool old_increasing_order = false;
4761  if (old_initial_arclength < old_final_arclength)
4762  {old_increasing_order = true;}
4763 
4764  // Now get the first and last node of the current segment
4765  // Get the first element
4766  FiniteElement* first_old_seg_ele_pt =
4767  old_segment_sorted_ele_pt[old_is].front();
4768 
4769  // Number of nodes
4770  const unsigned nnod = first_old_seg_ele_pt->nnode();
4771 
4772  // Get the first node of the current segment
4773  Node *first_old_seg_node_pt = first_old_seg_ele_pt->node_pt(0);
4774  if (old_is_inverted[first_old_seg_ele_pt])
4775  {
4776  first_old_seg_node_pt = first_old_seg_ele_pt->node_pt(nnod-1);
4777  }
4778 
4779  // Get access to the last element on the segment
4780  FiniteElement* last_old_seg_ele_pt =
4781  old_segment_sorted_ele_pt[old_is].back();
4782 
4783  // Get the last node of the current segment
4784  Node *last_old_seg_node_pt = last_old_seg_ele_pt->node_pt(nnod-1);
4785  if (old_is_inverted[last_old_seg_ele_pt])
4786  {
4787  last_old_seg_node_pt = last_old_seg_ele_pt->node_pt(0);
4788  }
4789  // Check if the segment is inverted, if that is the case then
4790  // also invert the nodes
4791  if (old_inverted_segment)
4792  {
4793  Node* temp_node_pt = first_old_seg_node_pt;
4794  first_old_seg_node_pt = last_old_seg_node_pt;
4795  last_old_seg_node_pt = temp_node_pt;
4796  }
4797 
4798  // We have the first and last node of the old segment (input
4799  // segment), now identify in which segment, of those with only
4800  // nonhalo face elements, they are
4801  for (unsigned is = 0; is < nsegments; is++)
4802  {
4803  if (!done_segment[is])
4804  {
4805  // Go through the nodes of the current segment and try to find
4806  // the old nodes
4807  bool found_first_old_seg_node = false;
4808  bool found_last_old_seg_node = false;
4809  bool same_order = false;
4810 
4811  // Get the first node of the current segment
4812  FiniteElement* first_seg_ele_pt = segment_sorted_ele_pt[is].front();
4813  Node* first_seg_node_pt = first_seg_ele_pt->node_pt(0);
4814  if (is_inverted[first_seg_ele_pt])
4815  {first_seg_node_pt = first_seg_ele_pt->node_pt(nnod-1);}
4816 
4817  // Get the arclength for the first node
4818  const double segment_first_node_zeta =
4819  sorted_segment_node_arclength[is][0];
4820 
4821  // Get the node coordinates for the first node
4822  Vector<double> first_node_coord(2);
4823  for (unsigned i = 0; i < 2; i++)
4824  {first_node_coord[i] = first_seg_node_pt->x(i);}
4825 
4826  // Get the last node of the current segment
4827  FiniteElement* last_seg_ele_pt = segment_sorted_ele_pt[is].back();
4828  Node* last_seg_node_pt = last_seg_ele_pt->node_pt(nnod-1);
4829  if (is_inverted[last_seg_ele_pt])
4830  {last_seg_node_pt = last_seg_ele_pt->node_pt(0);}
4831 
4832  // Get the arclength for the last node
4833  const double segment_final_node_zeta = segment_arclength[is];
4834 
4835  // Get the node coordinates for the last node
4836  Vector<double> last_node_coord(2);
4837  for (unsigned i = 0; i < 2; i++)
4838  {last_node_coord[i] = last_seg_node_pt->x(i);}
4839 
4840  // Temporary storage for the nodes of the current segment
4841  Vector<Node*> segment_node_pt = sorted_segment_all_nodes_pt[is];
4842  // Get the number of nodes in the segment
4843  const unsigned nsegment_node = segment_node_pt.size();
4844  for (unsigned in = 0; in < nsegment_node; in++)
4845  {
4846  Node* current_node_pt = segment_node_pt[in];
4847  if (!found_first_old_seg_node &&
4848  first_old_seg_node_pt == current_node_pt)
4849  {
4850  // Get the arclength assigned to the node on the old
4851  // segment
4852  const double current_node_zeta =
4853  sorted_segment_node_arclength[is][in];
4854 
4855  // Now check if the new segment has the same orientation
4856  // as the old one
4857  if (!found_last_old_seg_node) // has the same orientation
4858  {
4859  // Re-assign the first node coordinates
4860  Boundary_segment_initial_coordinate[b][is] = first_node_coord;
4861 
4862  // Check if the boundary has an associated GeomObject
4863  if (this->boundary_geom_object_pt(b)!=0)
4864  {
4865  // Assign the zeta values if the current segment has the
4866  // nodes of the old one
4867 
4868  // If we are in the same order then pass the values as
4869  // they are
4870  Boundary_segment_initial_zeta[b][is] =
4871  initial_zeta_segment[is];
4872 
4873  } // if (this->boundary_geom_object_pt(b)!=0)
4874  else
4875  {
4876  // Get the distance to the first node
4877  const double distance =
4878  std::fabs(current_node_zeta - segment_first_node_zeta);
4879 
4880  double new_initial_arclength = old_initial_arclength;
4881 
4882  // Now check if the zeta values are in increasing order
4883  if (old_increasing_order)
4884  {
4885  // Substract the distance
4886  new_initial_arclength-= distance;
4887  }
4888  else
4889  {
4890  // Add the distance
4891  new_initial_arclength+= distance;
4892  }
4893 
4894  // Re-assign the initial arclength for the current segment
4895  Boundary_segment_initial_arclength[b][is] =
4896  new_initial_arclength;
4897 
4898  } // else if (this->boundary_geom_object_pt(b)!=0)
4899  } // if (!found_last_old_seg_node)
4900  else // has different orientation
4901  {
4902  // Re-assign the first node coordinates
4903  Boundary_segment_initial_coordinate[b][is] = last_node_coord;
4904 
4905  // Check if the boundary has an associated GeomObject
4906  if (this->boundary_geom_object_pt(b)!=0)
4907  {
4908  // Assign the zeta values if the current segment has the
4909  // nodes of the old one
4910 
4911  // Not the same order, we need to copy the zeta values
4912  // from the other end, the inverted flag is changed at
4913  // the end. Copy the value from the final end
4914  Boundary_segment_initial_zeta[b][is] =
4915  final_zeta_segment[is];
4916 
4917  } // if (this->boundary_geom_object_pt(b)!=0)
4918  else
4919  {
4920  // Get the distance to the final node
4921  const double distance =
4922  std::fabs(current_node_zeta - segment_final_node_zeta);
4923 
4924  double new_initial_arclength = old_initial_arclength;
4925 
4926  // Now check if the zeta values are in increasing order
4927  if (old_increasing_order)
4928  {
4929  // Substract the distance
4930  new_initial_arclength-= distance;
4931  }
4932  else
4933  {
4934  // Add the distance
4935  new_initial_arclength+= distance;
4936  }
4937 
4938  // Re-assign the initial arclength for the current segment
4939  Boundary_segment_initial_arclength[b][is] =
4940  new_initial_arclength;
4941 
4942  } // else if (this->boundary_geom_object_pt(b)!=0)
4943  } // else if (!found_last_old_seg_node)
4944 
4945  // Mark as found the first node
4946  found_first_old_seg_node = true;
4947 
4948  }
4949  // if (!found_first_old_seg_node &&
4950  // first_old_seg_node_pt == current_node_pt)
4951 
4952  // If we found first the first node then the segments have
4953  // the same order
4954  if (found_first_old_seg_node && !found_last_old_seg_node)
4955  {same_order = true;}
4956 
4957  if (!found_last_old_seg_node &&
4958  last_old_seg_node_pt == current_node_pt)
4959  {
4960  // Get the boundary coordinates assigned to the node on
4961  // the old segment
4962  const double current_node_zeta =
4963  sorted_segment_node_arclength[is][in];
4964 
4965  // Now check if the new segment has the same orientation
4966  // as the old one
4967  if (found_first_old_seg_node) // has the same orientation
4968  {
4969  // Re-assign the last node coordinates
4970  Boundary_segment_final_coordinate[b][is] = last_node_coord;
4971 
4972  // Check if the boundary has an associated GeomObject
4973  if (this->boundary_geom_object_pt(b)!=0)
4974  {
4975  // Assign the zeta values if the current segment has the
4976  // nodes of the old one
4977 
4978  // If we are in the same order then pass the values as
4979  // they are
4980  Boundary_segment_final_zeta[b][is] =
4981  final_zeta_segment[is];
4982 
4983  } // if (this->boundary_geom_object_pt(b)!=0)
4984  else
4985  {
4986  // Get the distance to the last node
4987  const double distance =
4988  std::fabs(current_node_zeta - segment_final_node_zeta);
4989 
4990  double new_final_arclength = old_final_arclength;
4991 
4992  // Now check if the zeta values are in increasing order
4993  if (old_increasing_order)
4994  {
4995  // Add the distance
4996  new_final_arclength+= distance;
4997  }
4998  else
4999  {
5000  // Substract the distance
5001  new_final_arclength-= distance;
5002  }
5003 
5004  // Re-assign the final arclength for the current segment
5005  Boundary_segment_final_arclength[b][is] = new_final_arclength;
5006 
5007  } // else if (this->boundary_geom_object_pt(b)!=0)
5008  } // if (found_first_old_seg_node)
5009  else
5010  {
5011  // Re-assign the last node coordinates
5012  Boundary_segment_final_coordinate[b][is] = first_node_coord;
5013 
5014  // Check if the boundary has an associated GeomObject
5015  if (this->boundary_geom_object_pt(b)!=0)
5016  {
5017  // Assign the zeta values if the current segment has the
5018  // nodes of the old one
5019 
5020  // Not the same order, we need to copy the zeta values
5021  // from the other end, the inverted flag is changed at
5022  // the end. Copy the value from the initial end
5023  Boundary_segment_final_zeta[b][is] =
5024  initial_zeta_segment[is];
5025 
5026  } // if (this->boundary_geom_object_pt(b)!=0)
5027  else
5028  {
5029  // Get the distance to the last node
5030  const double distance =
5031  std::fabs(current_node_zeta - segment_first_node_zeta);
5032 
5033  double new_final_arclength = old_final_arclength;
5034 
5035  // Now check if the zeta values are in increasing order
5036  if (old_increasing_order)
5037  {
5038  // Add the distance
5039  new_final_arclength+= distance;
5040  }
5041  else
5042  {
5043  // Substract the distance
5044  new_final_arclength-= distance;
5045  }
5046 
5047  // Re-assign the final arclength for the current segment
5048  Boundary_segment_final_arclength[b][is] = new_final_arclength;
5049 
5050  } // else if (this->boundary_geom_object_pt(b)!=0)
5051  } // if (found_first_old_seg_node)
5052 
5053  // Mark as found the last node
5054  found_last_old_seg_node = true;
5055 
5056  } // if (!found_last_old_seg_node &&
5057  // last_old_seg_node_pt == current_node_pt)
5058 
5059  // If we found the last node first then the segments have
5060  // not the same order
5061  if (!found_first_old_seg_node && found_last_old_seg_node)
5062  {same_order = false;}
5063 
5064  if (found_first_old_seg_node && found_last_old_seg_node)
5065  {
5066  // Check if necessary to change the information that
5067  // states if a segment is inverted or not
5068  if (same_order)
5069  {Boundary_segment_inverted[b][is] = old_inverted_segment;}
5070  else
5071  {Boundary_segment_inverted[b][is] = !old_inverted_segment;}
5072 
5073  // Mark the segment as done
5074  done_segment[is] = true;
5075 
5076  // Increase the number of re-assigned segments
5077  re_assigned_segments++;
5078 
5079  // Break the for that look for the nodes in the segments
5080  break;
5081  }
5082 
5083  } // for (in < nsegment_node)
5084 
5085 #ifdef PARANOID
5086  if ((found_first_old_seg_node && !found_last_old_seg_node) ||
5087  (!found_first_old_seg_node && found_last_old_seg_node))
5088  {
5089  std::stringstream error_message;
5090  error_message
5091  << "Working with boundary ("<< b << ").\nOnly the first node or "
5092  << "the last node of the old segment (" << old_is << ") was\n"
5093  << "found. Both, first and last node should have been found in "
5094  << "the same segment!!!.\n"
5095  << "Found first seg node:" << found_first_old_seg_node << "\n"
5096  << "Found last seg node:" << found_last_old_seg_node << "\n\n";
5097  throw OomphLibError(error_message.str(),
5098  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
5099  OOMPH_EXCEPTION_LOCATION);
5100  }
5101 #endif
5102 
5103  } // if (!done_segment[is])
5104  } // for (is < nsegments)
5105  } // for (old_is < old_nsegments)
5106 
5107  // For those segments not identified set dummy values, the boundary
5108  // coordinates should be corrected at the synchronisation stage
5109 
5110  // loop over the new segments and check if there not identified
5111  // segments
5112  for (unsigned is = 0; is < nsegments; is++)
5113  {
5114  // Was the segment identified
5115  if (!done_segment[is])
5116  {
5117  // Get the first node of the current segment
5118  FiniteElement* first_seg_ele_pt =
5119  segment_sorted_ele_pt[is].front();
5120  // Number of nodes
5121  const unsigned nnod = first_seg_ele_pt->nnode();
5122 
5123  Node* first_seg_node_pt = first_seg_ele_pt->node_pt(0);
5124  if (is_inverted[first_seg_ele_pt])
5125  {first_seg_node_pt = first_seg_ele_pt->node_pt(nnod-1);}
5126 
5127  // Get the arclength for the first node
5128  const double segment_first_node_zeta =
5129  sorted_segment_node_arclength[is][0];
5130 
5131  // Get the node coordinates for the first node
5132  Vector<double> first_node_coord(2);
5133  for (unsigned i = 0; i < 2; i++)
5134  {first_node_coord[i] = first_seg_node_pt->x(i);}
5135 
5136  // Get the last node of the current segment
5137  FiniteElement* last_seg_ele_pt =
5138  segment_sorted_ele_pt[is].back();
5139  Node* last_seg_node_pt = last_seg_ele_pt->node_pt(nnod-1);
5140  if (is_inverted[last_seg_ele_pt])
5141  {last_seg_node_pt = last_seg_ele_pt->node_pt(0);}
5142 
5143  // Get the arclength for the last node
5144  const double segment_final_node_zeta = segment_arclength[is];
5145 
5146  // Get the node coordinates for the last node
5147  Vector<double> last_node_coord(2);
5148  for (unsigned i = 0; i < 2; i++)
5149  {last_node_coord[i] = last_seg_node_pt->x(i);}
5150 
5151  // Re-assign the initial node coordinates
5152  Boundary_segment_initial_coordinate[b][is] = first_node_coord;
5153 
5154  // Check if the boundary has an associated GeomObject
5155  if (this->boundary_geom_object_pt(b)!=0)
5156  {
5157  // Assign the zeta values if the current segment has the
5158  // nodes of the old one
5159 
5160  // If we are in the same order then pass the values as
5161  // they are
5162  Boundary_segment_initial_zeta[b][is] =
5163  initial_zeta_segment[is];
5164 
5165  } // if (this->boundary_geom_object_pt(b)!=0)
5166  else
5167  {
5168  // Re-assign the initial arclength for the current segment
5169  Boundary_segment_initial_arclength[b][is] =
5170  segment_first_node_zeta;
5171 
5172  } // else if (this->boundary_geom_object_pt(b)!=0)
5173 
5174  // Re-assign the initial node coordinates
5175  Boundary_segment_final_coordinate[b][is] = last_node_coord;
5176 
5177  // Check if the boundary has an associated GeomObject
5178  if (this->boundary_geom_object_pt(b)!=0)
5179  {
5180  // Assign the zeta values if the current segment has the
5181  // nodes of the old one
5182 
5183  // If we are in the same order then pass the values as
5184  // they are
5185  Boundary_segment_final_zeta[b][is] =
5186  final_zeta_segment[is];
5187 
5188  } // if (this->boundary_geom_object_pt(b)!=0)
5189  else
5190  {
5191  // Re-assign the final arclength for the current segment
5192  Boundary_segment_final_arclength[b][is] =
5193  segment_final_node_zeta;
5194 
5195  } // else if (this->boundary_geom_object_pt(b)!=0)
5196 
5197  Boundary_segment_inverted[b][is] = 0;
5198 
5199  // Mark the segment as done
5200  done_segment[is] = true;
5201 
5202  // Increase the number of re-assigned segments
5203  re_assigned_segments++;
5204 
5205  } // if (!done_segment[is])
5206 
5207  } // for (is < nsegments)
5208 
5209 #ifdef PARANOID
5210  // Compare the number of new segments identified with the old segments
5211  if (re_assigned_segments != nsegments)
5212  {
5213  std::stringstream error_message;
5214  error_message
5215  << "Working with boundary ("<< b << ").\nThe number of re-assigned "
5216  << "segments (" << re_assigned_segments
5217  << ") is different from the number\nof segments ("<< nsegments
5218  << ")\n\n";
5219  throw OomphLibError(error_message.str(),
5220  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
5221  OOMPH_EXCEPTION_LOCATION);
5222  } // if (re_assigned_segments != nsegments)
5223 #endif
5224 
5225  // Clean all the created face elements
5226  for (unsigned i = 0; i < nele; i++)
5227  {
5228  delete face_el_pt[i];
5229  face_el_pt[i] = 0;
5230  }
5231 
5232  }
5233 
5234  ///=====================================================================
5235  /// Select face elements from a given boundary. In case the we are
5236  /// dealing with an internal boundary we use a set of criterias to
5237  /// decide which of the two face elements should be used on represent
5238  /// the internal boundary. We return the face elements, halo or
5239  /// haloed on this processor that form the boundary. The caller method
5240  /// should be in charge of selecting nonhalo elements and deleting the face
5241  /// elements created by this method
5242  /// =====================================================================
5243  template <class ELEMENT>
5246  const unsigned &b,
5247  bool &is_internal_boundary,
5248  std::map<FiniteElement*,FiniteElement*>
5249  &face_to_bulk_element_pt)
5250  {
5251  // Get the communicator of the mesh
5252  OomphCommunicator* comm_pt = this->communicator_pt();
5253 
5254  const unsigned my_rank = comm_pt->my_rank();
5255 
5256  // ------------------------------------------------------------------
5257  // 1) Get the face elements associated with the current boundary
5258  // ------------------------------------------------------------------
5259 
5260  // Temporary storage for face elements (do not take care of
5261  // repeated face elements)
5262  Vector<FiniteElement*> tmp_face_ele_pt;
5263 
5264  const unsigned nregions = this->nregion();
5265 
5266  // If there is more than one region then only use boundary
5267  // coordinates from the bulk side (region 0)
5268  if (nregions > 1)
5269  {
5270  for (unsigned ir = 0 ; ir < nregions; ir++)
5271  {
5272  const unsigned region_id =
5273  static_cast<unsigned>(this->Region_attribute[ir]);
5274 
5275  // Loop over all elements on boundaries in region -ir-
5276  const unsigned nele_in_region =
5277  this->nboundary_element_in_region(b, region_id);
5278 
5279  // Only bother to do anything else, if there are elements
5280  // associated with the boundary and the current region
5281  if (nele_in_region > 0)
5282  {
5283  // Loop over the bulk elements adjacent to boundary b
5284  for (unsigned e = 0; e < nele_in_region; e++)
5285  {
5286  // Get pointer to the bulk element that is adjacent
5287  // to boundary b
5288  FiniteElement* bulk_ele_pt =
5289  this->boundary_element_in_region_pt(b, region_id, e);
5290 
5291  // Get the index of the face of element e along
5292  // boundary b
5293  int face_index =
5294  this->face_index_at_boundary_in_region(b,region_id,e);
5295 
5296  // Create the face element
5297  FiniteElement* tmp_face_el_pt =
5298  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5299 
5300  // Associated the face element with the bulk
5301  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5302 
5303  // ... and add it to the tmp storage for all the
5304  // face elements, do not take care for repeated
5305  // ones (at the moment)
5306  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5307 
5308  } // for (e < nele_in_region)
5309 
5310  } // if (nele_in_region > 0)
5311 
5312  } // for (ir < n_regions)
5313 
5314  } // if (n_regions > 1)
5315 
5316  //Otherwise it's just the normal boundary functions
5317  else
5318  {
5319  // Loop over all elements on boundaries
5320  const unsigned nbound_ele = this->nboundary_element(b);
5321 
5322  //Only bother to do anything else, if there are elements
5323  if (nbound_ele > 0)
5324  {
5325  // Loop over the bulk elements adjacent to boundary b
5326  for (unsigned e = 0; e < nbound_ele; e++)
5327  {
5328  // Get pointer to the bulk element that is adjacent to
5329  // boundary b
5330  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
5331 
5332  // Get the index of the face of element e along
5333  // boundary b
5334  int face_index = this->face_index_at_boundary(b, e);
5335 
5336  // Create the face element
5337  FiniteElement* tmp_face_el_pt =
5338  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5339 
5340  // Associated the face element with the bulk
5341  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5342 
5343  // ... and add it to the tmp storage for all the face
5344  // elements, do not care for repeated ones (at the
5345  // moment)
5346  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5347 
5348  } // (e < nbound_ele)
5349 
5350  } // (nbound_ele > 0)
5351 
5352  } // else (n_regions > 1)
5353 
5354  // map to know which face element has been already done
5355  std::map<FiniteElement*,bool> done_face;
5356 
5357  // Set the flag to indicate if we are working with an internal
5358  // boundary
5359  is_internal_boundary = false;
5360 
5361  // Free the memory of the elements in this container (only used
5362  // when working with internal boundaries)
5363  Vector<FiniteElement*> free_memory_face_ele_pt;
5364 
5365  // Get the number of face elements in the boundary (including
5366  // repeated)
5367  const unsigned n_tmp_face_ele = tmp_face_ele_pt.size();
5368  for (unsigned ie = 0; ie < n_tmp_face_ele; ie++)
5369  {
5370  // Get the possible main element
5371  FiniteElement* main_face_ele_pt = tmp_face_ele_pt[ie];
5372  if (!done_face[main_face_ele_pt])
5373  {
5374  // Mark the face element as done
5375  done_face[main_face_ele_pt] = true;
5376  // Get the number of nodes for the face element
5377  const unsigned nnodes = main_face_ele_pt->nnode();
5378  // Get the first and last node of the main face element
5379  Node* main_first_node_pt = main_face_ele_pt->node_pt(0);
5380  Node* main_last_node_pt = main_face_ele_pt->node_pt(nnodes-1);
5381  // Look for the other side face element (we can start from
5382  // the next one, all previous face elements have been
5383  // already identified with its other side face)
5384  for (unsigned iie = ie + 1; iie < n_tmp_face_ele; iie++)
5385  {
5386  // Get the possible dependant element
5387  FiniteElement* dependant_face_ele_pt = tmp_face_ele_pt[iie];
5388  if (!done_face[dependant_face_ele_pt])
5389  {
5390  // Get the first and last node of the dependant
5391  // face element
5392  Node* dependant_first_node_pt =
5393  dependant_face_ele_pt->node_pt(0);
5394  Node* dependant_last_node_pt =
5395  dependant_face_ele_pt->node_pt(nnodes-1);
5396  // Check if the nodes at the ends of both face
5397  // elements match (also check the reversed case)
5398  if (((dependant_first_node_pt == main_first_node_pt) &&
5399  (dependant_last_node_pt == main_last_node_pt)) ||
5400  ((dependant_first_node_pt == main_last_node_pt) &&
5401  (dependant_last_node_pt == main_first_node_pt)))
5402  {
5403  // Set the flag to indicate we are working with an
5404  // internal boundary
5405  is_internal_boundary = true;
5406  // Mark the face element as done
5407  done_face[dependant_face_ele_pt] = true;
5408 
5409  // Now choose which face element will be used
5410  // as the main element. We get the processor in
5411  // charge of the element and choose the one
5412  // with the highest processor in charge or the
5413  // bottom-left bulk element in case the both
5414  // faces are on the same processor
5415 
5416  // Get the bulk element for each face element
5417  // (the main and the dependant face element)
5418  FiniteElement *main_bulk_ele_pt =
5419  face_to_bulk_element_pt[main_face_ele_pt];
5420  FiniteElement *dependant_bulk_ele_pt =
5421  face_to_bulk_element_pt[dependant_face_ele_pt];
5422 
5423  // Get the processor in charge for each bulk
5424  // element
5425  int processor_in_charge_main_bulk_ele =
5426  main_bulk_ele_pt->non_halo_proc_ID();
5427  int processor_in_charge_dependant_bulk_ele =
5428  dependant_bulk_ele_pt->non_halo_proc_ID();
5429 
5430  // If the processor in charge is negative the
5431  // element is not halo, therefore the processor
5432  // in charge is the current one
5433  if (processor_in_charge_main_bulk_ele < 0)
5434  {
5435  processor_in_charge_main_bulk_ele=
5436  static_cast<int>(my_rank);
5437  }
5438  if (processor_in_charge_dependant_bulk_ele < 0)
5439  {
5440  processor_in_charge_dependant_bulk_ele=
5441  static_cast<int>(my_rank);
5442  }
5443 
5444  // Flag to know if add the main or dependant
5445  // face element
5446  bool add_main_face_element = true;
5447  if (processor_in_charge_dependant_bulk_ele >
5448  processor_in_charge_main_bulk_ele)
5449  {
5450  // Include the dependant element
5451  add_main_face_element = false;
5452  }
5453  else if (processor_in_charge_main_bulk_ele ==
5454  processor_in_charge_dependant_bulk_ele)
5455  {
5456  // When the processor in charge for both
5457  // elements is the same then use the
5458  // bottom-left criteria on the bulk
5459  // elements to choose the main face element
5460  Vector<double> main_ele_coordinates(2);
5461  Vector<double> dependant_ele_coordinates(2);
5462  // Get the number of nodes on the bulk
5463  // elements
5464  const unsigned n_bulk_nodes =
5465  main_bulk_ele_pt->nnode();
5466  for (unsigned inode = 0; inode < n_bulk_nodes;
5467  inode++)
5468  {
5469  for (unsigned idim = 0; idim < 2; idim++)
5470  {
5471  main_ele_coordinates[idim]+=
5472  main_bulk_ele_pt->node_pt(inode)->
5473  x(idim);
5474  dependant_ele_coordinates[idim]+=
5475  dependant_bulk_ele_pt->node_pt(inode)->
5476  x(idim);
5477  } // (idim < 2)
5478 
5479  } // (inode < n_bulk_nodes)
5480 
5481  // Get the average of the nodes coordinates
5482  for (unsigned idim = 0; idim < 2; idim++)
5483  {
5484  main_ele_coordinates[idim]/=
5485  (double)n_bulk_nodes;
5486  dependant_ele_coordinates[idim]/=
5487  (double)n_bulk_nodes;
5488  }
5489 
5490  // Once we know the average coordinates for
5491  // each element then we choose the one with
5492  // the bottom-left averaged coordinates
5493  if (dependant_ele_coordinates[1] <
5494  main_ele_coordinates[1])
5495  {add_main_face_element = false;}
5496  else if(dependant_ele_coordinates[1]==
5497  main_ele_coordinates[1])
5498  {
5499  // The left-most element
5500  if(dependant_ele_coordinates[0] <
5501  main_ele_coordinates[0])
5502  {add_main_face_element = false;}
5503  }
5504  } // else -- The processor in charge is the
5505  // same for both elements
5506 
5507  if (add_main_face_element)
5508  {
5509  // Add the main face element to the storage
5510  // so we get the halo and haloed nodes from
5511  // it
5512  face_ele_pt.push_back(main_face_ele_pt);
5513  // Mark the dependat face element to free
5514  // its memory
5515  free_memory_face_ele_pt.
5516  push_back(dependant_face_ele_pt);
5517  }
5518  else
5519  {
5520  // Add the dependant face element to the
5521  // storage so we get the halo and haloed
5522  // nodes from it
5523  face_ele_pt.push_back(dependant_face_ele_pt);
5524  // Mark the main face element to free its
5525  // memory
5526  free_memory_face_ele_pt.
5527  push_back(main_face_ele_pt);
5528  }
5529 
5530  // Break the for to look for the next face
5531  // element
5532  break;
5533 
5534  } // if -- matching of nodes from main ele and
5535  // dependant ele
5536 
5537  } // if (!done_face[dependant_face_ele_pt])
5538 
5539  } // for (iie < n_tmp_face_ele)
5540 
5541  } // if (!done_face[main_face_ele_pt])
5542 
5543  } // for (ie < n_tmp_face_ele)
5544 
5545  // Are there any face element to free its memory
5546  const unsigned n_free_face_ele = free_memory_face_ele_pt.size();
5547  if (n_free_face_ele == 0)
5548  {
5549  // If there is not face elements to free memory that means that
5550  // we are not working with an internal boundary, therefore copy
5551  // all the element from the tmp face elements into the face
5552  // elements container
5553 
5554  // Resize the container
5555  face_ele_pt.resize(n_tmp_face_ele);
5556  // loop over the elements and copy them
5557  for (unsigned i = 0; i < n_tmp_face_ele; i++)
5558  {
5559  face_ele_pt[i] = tmp_face_ele_pt[i];
5560  } // for (i < n_tmp_face_ele)
5561 
5562  } // if (n_free_face_ele == 0)
5563  else
5564  {
5565  // ... otherwise free the memory of the indicated elements
5566  // loop over the elements to free its memory
5567  for (unsigned i = 0; i < n_free_face_ele; i++)
5568  {
5569  delete free_memory_face_ele_pt[i];
5570  free_memory_face_ele_pt[i] = 0;
5571  } // for (i < n_free_face_ele)
5572  }
5573 
5574  }
5575 
5576  ///========================================================================
5577  /// In charge of sinchronize the boundary coordinates for internal
5578  /// boundaries that were split as part of the distribution
5579  /// process. Called after setup_boundary_coordinates() for the
5580  /// original mesh only
5581  ///========================================================================
5582  template <class ELEMENT>
5585  {
5586  // ------------------------------------------------------------------
5587  // First: Get the face elements associated with the current boundary
5588  // ------------------------------------------------------------------
5589 
5590  // Get the communicator of the mesh
5591  OomphCommunicator* comm_pt = this->communicator_pt();
5592 
5593  const unsigned nproc = comm_pt->nproc();
5594  const unsigned my_rank = comm_pt->my_rank();
5595 
5596  // Temporary storage for face elements (do not take care of repeated
5597  // face elements)
5598  Vector<FiniteElement*> tmp_face_ele_pt;
5599 
5600  const unsigned nregions = this->nregion();
5601 
5602  // map to associate the face element to the bulk element, necessary
5603  // to get the processor in charge for the halo elements
5604  std::map<FiniteElement*,FiniteElement*> face_to_bulk_element_pt;
5605 
5606  // If there is more than one region then only use boundary
5607  // coordinates from the bulk side (region 0)
5608  if (nregions > 1)
5609  {
5610  for (unsigned ir = 0 ; ir < nregions; ir++)
5611  {
5612  const unsigned region_id =
5613  static_cast<unsigned>(this->Region_attribute[ir]);
5614 
5615  // Loop over all elements on boundaries in region -ir-
5616  const unsigned nele_in_region =
5617  this->nboundary_element_in_region(b, region_id);
5618 
5619  // Only bother to do anything else, if there are elements
5620  // associated with the boundary and the current region
5621  if (nele_in_region > 0)
5622  {
5623  // Loop over the bulk elements adjacent to boundary b
5624  for (unsigned e = 0; e < nele_in_region; e++)
5625  {
5626  // Get pointer to the bulk element that is adjacent to boundary b
5627  FiniteElement* bulk_ele_pt =
5628  this->boundary_element_in_region_pt(b, region_id, e);
5629 
5630  // Get the index of the face of element e along boundary b
5631  int face_index=this->face_index_at_boundary_in_region(b,region_id,e);
5632 
5633  // Create the face element
5634  FiniteElement* tmp_face_el_pt =
5635  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5636 
5637  // ... and add it to the tmp storage for all the face
5638  // elements, do not take care for repeated ones (at the
5639  // moment)
5640  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5641  // Create the map to know if the element is halo
5642  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5643 
5644  } // for (e < nele_in_region)
5645 
5646  } // if (nele_in_region > 0)
5647 
5648  } // for (ir < n_regions)
5649 
5650  } // if (n_regions > 1)
5651 
5652  //Otherwise it's just the normal boundary functions
5653  else
5654  {
5655  // Loop over all elements on boundaries
5656  const unsigned nbound_ele = this->nboundary_element(b);
5657 
5658  //Only bother to do anything else, if there are elements
5659  if (nbound_ele > 0)
5660  {
5661  // Loop over the bulk elements adjacent to boundary b
5662  for (unsigned e = 0; e < nbound_ele; e++)
5663  {
5664  // Get pointer to the bulk element that is adjacent to boundary b
5665  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
5666 
5667  // Get the index of the face of element e along boundary b
5668  int face_index = this->face_index_at_boundary(b, e);
5669 
5670  // Create the face element
5671  FiniteElement* tmp_face_el_pt =
5672  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5673 
5674  // ... and add it to the tmp storage for all the face
5675  // elements, do not care for repeated ones (at the moment)
5676  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5677  // Create the map to know if the element is halo
5678  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5679 
5680  } // (e < nbound_ele)
5681 
5682  } // (nbound_ele > 0)
5683 
5684  } // else (n_regions > 1)
5685 
5686  // Temporary storage for one side face elements. In case we are
5687  // working with an internal boundary here we store only one of the
5688  // face elements that are at each side of the boundary
5689  Vector<FiniteElement*> face_ele_pt;
5690 
5691  // map to know which face element has been already done
5692  std::map<FiniteElement*,bool> done_face;
5693 
5694  // Flag to indicate if we are working with an internal boundary
5695  bool is_internal_boundary = false;
5696 
5697 #ifdef PARANOID
5698  // Flag to indicate if we are working with an internal boundary (paranoid)
5699  bool is_internal_boundary_paranoid = false;
5700 
5701  // Count the number of other side face elements found in case we are
5702  // working with an internal boundary
5703  unsigned nfound_face_elements = 0;
5704 #endif
5705 
5706  // Get the number of face elements in the boundary
5707  const unsigned nbound_ele = tmp_face_ele_pt.size();
5708  for (unsigned ie = 0; ie < nbound_ele; ie++)
5709  {
5710  // Get the possible main element
5711  FiniteElement* main_face_ele_pt = tmp_face_ele_pt[ie];
5712  if (!done_face[main_face_ele_pt])
5713  {
5714  // Mark the face element as done
5715  done_face[main_face_ele_pt] = true;
5716  // Get the number of nodes for the face element
5717  const unsigned nnodes = main_face_ele_pt->nnode();
5718  // Get the first and last node of the main face element
5719  Node* main_first_node_pt = main_face_ele_pt->node_pt(0);
5720  Node* main_last_node_pt = main_face_ele_pt->node_pt(nnodes-1);
5721  // Look for the other side face element
5722  for (unsigned iie = ie + 1; iie < nbound_ele; iie++)
5723  {
5724  // Get the possible dependant element
5725  FiniteElement* dependant_face_ele_pt = tmp_face_ele_pt[iie];
5726  if (!done_face[dependant_face_ele_pt])
5727  {
5728  // Get the first and last node of the dependant face element
5729  Node* dependant_first_node_pt =
5730  dependant_face_ele_pt->node_pt(0);
5731  Node* dependant_last_node_pt =
5732  dependant_face_ele_pt->node_pt(nnodes-1);
5733  // Check if the nodes at the ends of both face elements
5734  // match (also check the reversed case)
5735  if (((dependant_first_node_pt == main_first_node_pt) &&
5736  (dependant_last_node_pt == main_last_node_pt)) ||
5737  ((dependant_first_node_pt == main_last_node_pt) &&
5738  (dependant_last_node_pt == main_first_node_pt)))
5739  {
5740 #ifdef PARANOID
5741  // Increase the number of found face elements
5742  nfound_face_elements+=2;
5743 #endif
5744  // Set the flag to indicate we are working with an
5745  // internal boundary
5746  is_internal_boundary = true;
5747  // Mark the face element as done
5748  done_face[dependant_face_ele_pt] = true;
5749 
5750  // Now choose which face element will be used as the main
5751  // element. Use the same criteria as the compute segments
5752  // connectivity method (highest processor in charge or
5753  // bottom-left bulk element)
5754 
5755  // Get the bulk element for each face element (the main
5756  // and the dependant face element)
5757  FiniteElement *main_bulk_ele_pt =
5758  face_to_bulk_element_pt[main_face_ele_pt];
5759  FiniteElement *dependant_bulk_ele_pt =
5760  face_to_bulk_element_pt[dependant_face_ele_pt];
5761 
5762  // Get the processor in charge for each bulk element
5763  int processor_in_charge_main_bulk_ele =
5764  main_bulk_ele_pt->non_halo_proc_ID();
5765  int processor_in_charge_dependant_bulk_ele =
5766  dependant_bulk_ele_pt->non_halo_proc_ID();
5767 
5768  // If the processor in charge is negative the element is
5769  // not halo, therefore the processor in charge is the
5770  // current one
5771  if (processor_in_charge_main_bulk_ele < 0)
5772  {
5773  processor_in_charge_main_bulk_ele=static_cast<int>(my_rank);
5774  }
5775  if (processor_in_charge_dependant_bulk_ele < 0)
5776  {
5777  processor_in_charge_dependant_bulk_ele=static_cast<int>(my_rank);
5778  }
5779 
5780  // Flag to know if add the main or dependant face element
5781  bool add_main_face_element = true;
5782  if (processor_in_charge_dependant_bulk_ele >
5783  processor_in_charge_main_bulk_ele)
5784  {
5785  // Include the dependant element
5786  add_main_face_element = false;
5787  }
5788  else if (processor_in_charge_main_bulk_ele ==
5789  processor_in_charge_dependant_bulk_ele)
5790  {
5791  // When the processor in charge for both elements is the same
5792  // then use the bottom-left criteria on the bulk elements to
5793  // choose the main face element
5794  Vector<double> main_ele_coordinates(2);
5795  Vector<double> dependant_ele_coordinates(2);
5796  // Get the number of nodes on the bulk elements
5797  const unsigned n_bulk_nodes = main_bulk_ele_pt->nnode();
5798  for (unsigned inode = 0; inode < n_bulk_nodes; inode++)
5799  {
5800  for (unsigned idim = 0; idim < 2; idim++)
5801  {
5802  main_ele_coordinates[idim]+=
5803  main_bulk_ele_pt->node_pt(inode)->x(idim);
5804  dependant_ele_coordinates[idim]+=
5805  dependant_bulk_ele_pt->node_pt(inode)->x(idim);
5806  } // (idim < 2)
5807  } // (inode < n_bulk_nodes)
5808 
5809  // Get the average of the nodes coordinates
5810  for (unsigned idim = 0; idim < 2; idim++)
5811  {
5812  main_ele_coordinates[idim]/=(double)n_bulk_nodes;
5813  dependant_ele_coordinates[idim]/=(double)n_bulk_nodes;
5814  }
5815 
5816  // Once we know the average coordinates for each element
5817  // then we choose the one with the bottom-left averaged
5818  // coordinates
5819  if (dependant_ele_coordinates[1] < main_ele_coordinates[1])
5820  {add_main_face_element = false;}
5821  else if(dependant_ele_coordinates[1]==main_ele_coordinates[1])
5822  {
5823  // The left-most element
5824  if(dependant_ele_coordinates[0] < main_ele_coordinates[0])
5825  {add_main_face_element = false;}
5826  }
5827  } // else -- The processor in charge is the same for both
5828  // elements
5829 
5830  if (add_main_face_element)
5831  {
5832  // Add the main face element to the storage so we get
5833  // the halo and haloed nodes from these face element
5834  face_ele_pt.push_back(main_face_ele_pt);
5835  }
5836  else
5837  {
5838  // Add the main face element to the storage so we get
5839  // the halo and haloed nodes from these face element
5840  face_ele_pt.push_back(dependant_face_ele_pt);
5841  }
5842 
5843  // Break the for to look for the next face element
5844  break;
5845 
5846  } // if -- matching of nodes from main ele and dependant ele
5847  } // if (!done_face[dependant_face_ele_pt])
5848  } // for (iie < nbound_ele)
5849  } // if (!done_face[main_face_ele_pt])
5850  } // for (ie < nbound_ele)
5851 
5852  // Get the number of face elements
5853  const unsigned nface_ele = face_ele_pt.size();
5854 
5855 #ifdef PARANOID
5856  // Check if we are working with an internal open curve. First check
5857  // if there are elements, in a distributed approach they may be no
5858  // elements associated to the boundary
5859  if (nbound_ele > 0 && nfound_face_elements == nbound_ele)
5860  {is_internal_boundary_paranoid = true;}
5861 
5862  if (nbound_ele > 0 && is_internal_boundary_paranoid &&
5863  nbound_ele!=nface_ele*2)
5864  {
5865  std::ostringstream error_message;
5866  error_message
5867  << "The info. to perform the synchronisation of the boundary "
5868  << "coordinates was not completely established\n"
5869  << "In this case it was the number of non repeated boundary elements\n"
5870  << "Number of boundary elements: (" << nbound_ele << ")\n"
5871  << "Number of nonrepeated boundary elements: (" << nface_ele << ")\n";
5872  throw OomphLibError(error_message.str(),
5873  "TriangleMesh::synchronize_boundary_coordinates()",
5874  OOMPH_EXCEPTION_LOCATION);
5875  }
5876 #endif
5877 
5878  // ----------------------------------------------------------------
5879  // Second: Identify the halo face elements
5880  // ----------------------------------------------------------------
5881 
5882  // A flag vector to mark those face elements that are considered as
5883  // halo in the current processor
5884  std::vector<bool> is_halo_face_element(nface_ele, false);
5885 
5886  // Count the total number of non halo face elements
5887  unsigned nnon_halo_face_elements = 0;
5888 
5889  for (unsigned ie = 0; ie < nface_ele; ie++)
5890  {
5891  FiniteElement* face_el_pt = face_ele_pt[ie];
5892  // Get the bulk element
5893  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_el_pt];
5894  // Check if the bulk element is halo
5895  if (!tmp_bulk_ele_pt->is_halo())
5896  {
5897  is_halo_face_element[ie] = false;
5898  nnon_halo_face_elements++;
5899  }
5900  else
5901  {
5902  // Mark the face element as halo
5903  is_halo_face_element[ie] = true;
5904  }
5905  } // for (ie < nface_ele)
5906 
5907  // -----------------------------------------------------------------
5908  // Third: Go through the face elements and get the nodes from the
5909  // elements. The boundary coordinate from each node is sent to its
5910  // processor in charge, then that processor will be responsible to
5911  // send the bound coordinate to all the processors that have a halo
5912  // representation of the node
5913  // -----------------------------------------------------------------
5914 
5915  // A map to know which nodes are already done
5916  std::map<Node*,bool> done_node;
5917 
5918  // The storage for the halo nodes on face elements in this processor
5919  // with other processors
5920  Vector<Vector<Node*> > face_halo_node_pt(nproc);
5921 
5922  // The storage for the ids of the halo nodes on face elements in
5923  // this processor with other processors
5924  Vector<Vector<unsigned> > face_halo_node_id(nproc);
5925 
5926  // The storage for the haloed nodes on face elements in this
5927  // processor with other processors
5928  Vector<Vector<Node*> > face_haloed_node_pt(nproc);
5929 
5930  // The storage for the ids of the haloed nodes on face elements in
5931  // this processor with other processors
5932  Vector<Vector<unsigned> > face_haloed_node_id(nproc);
5933 
5934  // A map to know which nodes are face nodes and the processor in
5935  // charge is the current one
5936  std::map<Node*,bool> done_haloed_face_node;
5937 
5938  // Go through all the face elements
5939  for (unsigned iface = 0; iface < nface_ele; iface++)
5940  {
5941  // Only work with the non halo face elements
5942  if (!is_halo_face_element[iface])
5943  {
5944  // Get the face element
5945  FiniteElement *ele_face_pt = face_ele_pt[iface];
5946  // The number of nodes of the face elements
5947  const unsigned nnodes = ele_face_pt->nnode();
5948  // Go through all the nodes in the face element
5949  for (unsigned in = 0; in < nnodes; in++)
5950  {
5951  Node* face_node_pt = ele_face_pt->node_pt(in);
5952  // Check if node is done
5953  if (!done_node[face_node_pt])
5954  {
5955  // Mark the node as done
5956  done_node[face_node_pt] = true;
5957  // First check if the node is halo
5958  if (face_node_pt->is_halo())
5959  {
5960  // Get the processor in charge for the current node
5961  int int_nonhalo_ID = face_node_pt->non_halo_proc_ID();
5962 #ifdef PARANOID
5963  if (int_nonhalo_ID < 0)
5964  {
5965  std::ostringstream error_message;
5966  error_message
5967  << "The node was marked to be halo but the processor in "
5968  << "charge was found to be -1\n\n";
5969  throw OomphLibError(error_message.str(),
5970  "TriangleMesh::synchronize_boundary_coordinates()",
5971  OOMPH_EXCEPTION_LOCATION);
5972  }
5973 #endif
5974  const unsigned ip = static_cast<unsigned>(int_nonhalo_ID);
5975  // Add the node to the structure that holds the halo
5976  // nodes, the current processor will need to send the
5977  // info. to the processor in charge.
5978  face_halo_node_pt[ip].push_back(face_node_pt);
5979  // ... finally look for the halo id with the processor in
5980  // charge
5981 #ifdef PARANOID
5982  bool found_halo_node = false;
5983 #endif
5984  const unsigned nhalo_iproc = this->nhalo_node(ip);
5985  for (unsigned ihn = 0; ihn < nhalo_iproc; ihn++)
5986  {
5987  Node* compare_face_node_pt = this->halo_node_pt(ip, ihn);
5988  if (compare_face_node_pt == face_node_pt)
5989  {
5990  // Once found the id of the node with the processor
5991  // store the id in the proper storage
5992  face_halo_node_id[ip].push_back(ihn);
5993 #ifdef PARANOID
5994  // Set the flag to mark as found the halo node
5995  found_halo_node = true;
5996 #endif
5997  // Break the loop
5998  break;
5999  }
6000  } // for (ih < nhalo_iproc)
6001 #ifdef PARANOID
6002  if (!found_halo_node)
6003  {
6004  std::ostringstream error_message;
6005  error_message
6006  << "The halo id of the current node: ("
6007  << face_node_pt->x(0) << ", " << face_node_pt->x(1)
6008  << ") with processor (" << ip << ") was not found!!!\n\n";
6009  throw OomphLibError(error_message.str(),
6010  "TriangleMesh::synchronize_boundary_coordinates()",
6011  OOMPH_EXCEPTION_LOCATION);
6012  }
6013 #endif
6014  } // if (face_node_pt->is_halo())
6015  // If the node is not halo then it could be haloed. If that
6016  // is the case then store the processors at which the node
6017  // is haloed and its id. The info. of these nodes will be
6018  // sent to all the processors with a halo counterpart
6019  else
6020  {
6021  for (unsigned ip = 0; ip < nproc; ip++)
6022  {
6023  // Only work with processors different that the current one
6024  if (ip != my_rank)
6025  {
6026  // If the node is found to be haloed with the "ip"
6027  // processor then save the haloed id in the storage.
6028  // The current processor needs to send info. to the
6029  // other processors to establish the boundary
6030  // coordinates
6031 
6032  // Get the number of haloed nodes with processor ip
6033  const unsigned nhaloed_iproc = this->nhaloed_node(ip);
6034  for (unsigned ihdn = 0; ihdn < nhaloed_iproc; ihdn++)
6035  {
6036  Node* compare_face_node_pt=this->haloed_node_pt(ip, ihdn);
6037  if (face_node_pt == compare_face_node_pt)
6038  {
6039  // Store the node on the haloed node vector for
6040  // the corresponding processor
6041  face_haloed_node_pt[ip].push_back(face_node_pt);
6042  // Now store the halo id of the node with the
6043  // current processor
6044  face_haloed_node_id[ip].push_back(ihdn);
6045  // Mark the node as haloed with other processors,
6046  // so we know the processor in charge is the
6047  // current one "my_rank".
6048  done_haloed_face_node[face_node_pt] = true;
6049  // Break looking in the current processor, look in
6050  // the next one
6051  break;
6052  } // if (face_node_pt == compare_face_node_pt)
6053  } // for (ihdn < nhaloed_node_iproc)
6054  } // if (ip != my_rank)
6055  } // for (ip < nproc)
6056  } // else (non halo node)
6057  } // if (!done_node[node_face_pt])
6058  } // for (in < nnodes)
6059  } // if (!is_halo_face_element[iface])
6060  } // for (iface < nface_ele)
6061 
6062  // -----------------------------------------------------------------
6063  // Fourth: Go through the halo nodes, package and send the
6064  // info. necessary to identify the face nodes in the processor in
6065  // charge. Identify the haloed nodes in the processor in charge and
6066  // establish the boundary coordinates, check if those nodes are
6067  // (already) marked as faced nodes, if that is the case then do not
6068  // establish the boundary coordinates but register them to send back
6069  // the info. to all the processors that have a halo representation
6070  // of the face node
6071  // -----------------------------------------------------------------
6072 
6073  // Go through all processors
6074  for (unsigned ip = 0; ip < nproc; ip++)
6075  {
6076  // Only work with processors different than the current one
6077  if (ip != my_rank)
6078  {
6079  const unsigned nhalo_face_nodes = face_halo_node_pt[ip].size();
6080 #ifdef PARANOID
6081  if (nhalo_face_nodes!=face_halo_node_id[ip].size())
6082  {
6083  std::ostringstream error_message;
6084  error_message
6085  << "The number of found halo face nodes (" << nhalo_face_nodes
6086  << ") is different from the number of\nfound halo face ids ("
6087  << face_halo_node_id[ip].size() << ")!!!\n\n";
6088  throw OomphLibError(error_message.str(),
6089  "TriangleMesh::synchronize_boundary_coordinates()",
6090  OOMPH_EXCEPTION_LOCATION);
6091  }
6092 #endif
6093 
6094  // Container to send the info. related with the halo nodes to be
6095  // identified in the processors in charge
6096  Vector<unsigned> flat_unsigned_send_packed_data;
6097  Vector<double> flat_double_send_packed_data;
6098 
6099  // Go through the halo face nodes in the "ip" processor
6100  for (unsigned ihfn = 0; ihfn < nhalo_face_nodes; ihfn++)
6101  {
6102  // Get the "ihfn"-th face node with the "ip" processor
6103  Node *halo_face_node_pt = face_halo_node_pt[ip][ihfn];
6104  // Get the halo id with the "ip" processor
6105  const unsigned halo_id = face_halo_node_id[ip][ihfn];
6106  // Get the boundary coordinate of the node
6107  Vector<double> zeta(1);
6108  halo_face_node_pt->get_coordinates_on_boundary(b, zeta);
6109  // Store the info. in the containers
6110  flat_unsigned_send_packed_data.push_back(halo_id);
6111  flat_double_send_packed_data.push_back(zeta[0]);
6112  }
6113 
6114  // Send the info.
6115  MPI_Status status;
6116  MPI_Request request;
6117 
6118  // Processor to which send the info
6119  int send_proc = static_cast<int>(ip);
6120  // Processor from which receive the info
6121  int receive_proc = static_cast<int>(ip);
6122 
6123  // Storage to receive the info.
6124  Vector<unsigned> flat_unsigned_receive_packed_data;
6125  Vector<double> flat_double_receive_packed_data;
6126 
6127  // --------------
6128  // Unsigned data
6129  unsigned nflat_unsigned_send = flat_unsigned_send_packed_data.size();
6130  MPI_Isend(&nflat_unsigned_send,1,MPI_UNSIGNED,
6131  send_proc,1,comm_pt->mpi_comm(),&request);
6132 
6133  unsigned nflat_unsigned_receive = 0;
6134  MPI_Recv(&nflat_unsigned_receive,1,MPI_UNSIGNED,
6135  receive_proc,1,comm_pt->mpi_comm(),&status);
6136 
6137  MPI_Wait(&request,MPI_STATUS_IGNORE);
6138 
6139  if (nflat_unsigned_send!=0)
6140  {
6141  MPI_Isend(&flat_unsigned_send_packed_data[0],nflat_unsigned_send,
6142  MPI_UNSIGNED,send_proc,2,comm_pt->mpi_comm(),&request);
6143  }
6144 
6145  if (nflat_unsigned_receive!=0)
6146  {
6147  flat_unsigned_receive_packed_data.resize(nflat_unsigned_receive);
6148  MPI_Recv(&flat_unsigned_receive_packed_data[0],nflat_unsigned_receive,
6149  MPI_UNSIGNED,receive_proc,2,comm_pt->mpi_comm(),&status);
6150  }
6151 
6152  if (nflat_unsigned_send!=0)
6153  {
6154  MPI_Wait(&request,MPI_STATUS_IGNORE);
6155  }
6156 
6157  // --------------
6158  // Double data
6159  unsigned nflat_double_send = flat_double_send_packed_data.size();
6160  MPI_Isend(&nflat_double_send,1,MPI_DOUBLE,
6161  send_proc,3,comm_pt->mpi_comm(),&request);
6162 
6163  unsigned nflat_double_receive = 0;
6164  MPI_Recv(&nflat_double_receive,1,MPI_DOUBLE,
6165  receive_proc,3,comm_pt->mpi_comm(),&status);
6166 
6167  MPI_Wait(&request,MPI_STATUS_IGNORE);
6168 
6169  if (nflat_double_send!=0)
6170  {
6171  MPI_Isend(&flat_double_send_packed_data[0],nflat_double_send,
6172  MPI_DOUBLE,send_proc,4,comm_pt->mpi_comm(),&request);
6173  }
6174 
6175  if (nflat_double_receive!=0)
6176  {
6177  flat_double_receive_packed_data.resize(nflat_double_receive);
6178  MPI_Recv(&flat_double_receive_packed_data[0],nflat_double_receive,
6179  MPI_DOUBLE,receive_proc,4,comm_pt->mpi_comm(),&status);
6180  }
6181 
6182  if (nflat_double_send!=0)
6183  {
6184  MPI_Wait(&request,MPI_STATUS_IGNORE);
6185  }
6186  // --------------
6187 
6188 #ifdef PARANOID
6189  if (nflat_unsigned_receive!=nflat_double_receive)
6190  {
6191  std::ostringstream error_message;
6192  error_message
6193  << "The number of unsigned received data ("
6194  << nflat_unsigned_receive << ") is different from the "
6195  << "number\nof double received data ("
6196  << nflat_double_receive << ")!!!\n\n";
6197  throw OomphLibError(error_message.str(),
6198  "TriangleMesh::synchronize_boundary_coordinates()",
6199  OOMPH_EXCEPTION_LOCATION);
6200  }
6201 #endif
6202 
6203  // With the received info. establish the boundary coordinates
6204  // for the face nodes that this processor is in charge (haloed
6205  // nodes)
6206  for (unsigned iflat_packed = 0; iflat_packed < nflat_unsigned_receive;
6207  iflat_packed++)
6208  {
6209  // Get the haloed id for the node
6210  const unsigned haloed_id =
6211  flat_unsigned_receive_packed_data[iflat_packed];
6212  // Get the boundary coordinates
6213  Vector<double> zeta(1);
6214  zeta[0] = flat_double_receive_packed_data[iflat_packed];
6215 
6216  // Get the haloed node
6217  Node* haloed_face_node_pt = this->haloed_node_pt(ip, haloed_id);
6218 
6219  // If the node has already set the boundary coordinates then
6220  // do not establish it. This is the case for the nodes that
6221  // lie on the boundary, for those nodes not identified on the
6222  // boundary since no elements lie on the boundary but the node
6223  // is on the boundary (a corner of an element lies on the
6224  // boundary) set boundary coordinates and register them to
6225  // send their info. to the processors with a halo counterpart
6226 
6227  // If the node is not haloed face in the procesor in charge
6228  // then set the boundary coordinates and register the node to
6229  // send back the boundary coordinates to the processors with a
6230  // halo counterpart
6231  if (!done_haloed_face_node[haloed_face_node_pt])
6232  {
6233  // Establish the boundary coordinates
6234  haloed_face_node_pt->set_coordinates_on_boundary(b, zeta);
6235 
6236  // Look in all processors where the node could be halo
6237  for (unsigned iiproc = 0; iiproc < nproc; iiproc++)
6238  {
6239  // Only work with processors different than the current one
6240  if (iiproc != my_rank)
6241  {
6242  // Get the number of haloed nodes with processor iiproc
6243  const unsigned nhaloed_node_iiproc = this->nhaloed_node(iiproc);
6244  for (unsigned ihdn = 0; ihdn < nhaloed_node_iiproc; ihdn++)
6245  {
6246  Node* compare_haloed_node_pt=this->haloed_node_pt(iiproc,ihdn);
6247  if (haloed_face_node_pt == compare_haloed_node_pt)
6248  {
6249  // Store the node on the haloed node vector for the
6250  // corresponding processor
6251  face_haloed_node_pt[iiproc].push_back(haloed_face_node_pt);
6252  // Now store the halo id of the node with the current
6253  // processor
6254  face_haloed_node_id[iiproc].push_back(ihdn);
6255  // Break searching in the current processor, search in
6256  // the next one
6257  break;
6258  }// if (haloed_face_node_pt==compare_haloed_face_node_pt)
6259  } // for (ihdn < nhaloed_node_iproc)
6260  } // if (iiproc != my_rank)
6261  } // for (iiproc < nproc)
6262  } // if (!done_haloed_face_node[haloed_face_node_pt])
6263  } // for (iflat_packed < nflat_unsigned_receive)
6264  } // if (ip != my_rank)
6265  } // for (ip < nproc)
6266 
6267  // -----------------------------------------------------------------
6268  // Fifth: The boundary coordinates have been established in the
6269  // processors in charge of the nodes. Now each processor send back
6270  // the boundary coordinates to all the processors where there is a
6271  // halo representation of the node
6272  // -----------------------------------------------------------------
6273 
6274  // Go through all processors
6275  for (unsigned ip = 0; ip < nproc; ip++)
6276  {
6277  // Only work with processors different than the current one
6278  if (ip != my_rank)
6279  {
6280  // Container to send the info. of the haloed nodes to all the
6281  // processors
6282  Vector<unsigned> flat_unsigned_send_packed_data;
6283  Vector<double> flat_double_send_packed_data;
6284 
6285  // Get the total number of haloed face nodes with the "ip"
6286  // processor
6287  const unsigned nhaloed_face_nodes = face_haloed_node_pt[ip].size();
6288  // Go through the haloed face nodes in the "ip" processor
6289  for (unsigned ihdfn = 0; ihdfn < nhaloed_face_nodes; ihdfn++)
6290  {
6291  // Get the "ihdfn"-th face node with the "ip" processor
6292  Node *haloed_face_node_pt = face_haloed_node_pt[ip][ihdfn];
6293  // Get the haloed id with the "ip" processor
6294  const unsigned haloed_id = face_haloed_node_id[ip][ihdfn];
6295  // Get the boundary coordinate of the node
6296  Vector<double> zeta(1);
6297  haloed_face_node_pt->get_coordinates_on_boundary(b, zeta);
6298  // Store the info. in the containers
6299  flat_unsigned_send_packed_data.push_back(haloed_id);
6300  flat_double_send_packed_data.push_back(zeta[0]);
6301  }
6302 
6303  // Send the info.
6304  MPI_Status status;
6305  MPI_Request request;
6306 
6307  // Processor to which send the info
6308  int send_proc = static_cast<int>(ip);
6309  // Processor from which receive the info
6310  int receive_proc = static_cast<int>(ip);
6311 
6312  // Storage to receive the info.
6313  Vector<unsigned> flat_unsigned_receive_packed_data;
6314  Vector<double> flat_double_receive_packed_data;
6315 
6316  // --------------
6317  // Unsigned data
6318  unsigned nflat_unsigned_send = flat_unsigned_send_packed_data.size();
6319  MPI_Isend(&nflat_unsigned_send,1,MPI_UNSIGNED,
6320  send_proc,1,comm_pt->mpi_comm(),&request);
6321 
6322  unsigned nflat_unsigned_receive = 0;
6323  MPI_Recv(&nflat_unsigned_receive,1,MPI_UNSIGNED,
6324  receive_proc,1,comm_pt->mpi_comm(),&status);
6325 
6326  MPI_Wait(&request,MPI_STATUS_IGNORE);
6327 
6328  if (nflat_unsigned_send!=0)
6329  {
6330  MPI_Isend(&flat_unsigned_send_packed_data[0],nflat_unsigned_send,
6331  MPI_UNSIGNED,send_proc,2,comm_pt->mpi_comm(),&request);
6332  }
6333 
6334  if (nflat_unsigned_receive!=0)
6335  {
6336  flat_unsigned_receive_packed_data.resize(nflat_unsigned_receive);
6337  MPI_Recv(&flat_unsigned_receive_packed_data[0],nflat_unsigned_receive,
6338  MPI_UNSIGNED,receive_proc,2,comm_pt->mpi_comm(),&status);
6339  }
6340 
6341  if (nflat_unsigned_send!=0)
6342  {
6343  MPI_Wait(&request,MPI_STATUS_IGNORE);
6344  }
6345 
6346  // --------------
6347  // Double data
6348  unsigned nflat_double_send = flat_double_send_packed_data.size();
6349  MPI_Isend(&nflat_double_send,1,MPI_DOUBLE,
6350  send_proc,3,comm_pt->mpi_comm(),&request);
6351 
6352  unsigned nflat_double_receive = 0;
6353  MPI_Recv(&nflat_double_receive,1,MPI_DOUBLE,
6354  receive_proc,3,comm_pt->mpi_comm(),&status);
6355 
6356  MPI_Wait(&request,MPI_STATUS_IGNORE);
6357 
6358  if (nflat_double_send!=0)
6359  {
6360  MPI_Isend(&flat_double_send_packed_data[0],nflat_double_send,
6361  MPI_DOUBLE,send_proc,4,comm_pt->mpi_comm(),&request);
6362  }
6363 
6364  if (nflat_double_receive!=0)
6365  {
6366  flat_double_receive_packed_data.resize(nflat_double_receive);
6367  MPI_Recv(&flat_double_receive_packed_data[0],nflat_double_receive,
6368  MPI_DOUBLE,receive_proc,4,comm_pt->mpi_comm(),&status);
6369  }
6370 
6371  if (nflat_double_send!=0)
6372  {
6373  MPI_Wait(&request,MPI_STATUS_IGNORE);
6374  }
6375  // --------------
6376 
6377 #ifdef PARANOID
6378  if (nflat_unsigned_receive!=nflat_double_receive)
6379  {
6380  std::ostringstream error_message;
6381  error_message
6382  << "The number of unsigned received data ("
6383  << nflat_unsigned_receive << ") is different from the "
6384  << "number\nof double received data ("
6385  << nflat_double_receive << ")!!!\n\n";
6386  throw OomphLibError(error_message.str(),
6387  "TriangleMesh::synchronize_boundary_coordinates()",
6388  OOMPH_EXCEPTION_LOCATION);
6389  }
6390 #endif
6391 
6392  // With the received info. establish the boundary coordinates
6393  // received for the face nodes that this processor is not in
6394  // charge (halo nodes)
6395  for (unsigned iflat_packed = 0; iflat_packed < nflat_unsigned_receive;
6396  iflat_packed++)
6397  {
6398  // Get the halo id for the node
6399  const unsigned halo_id =
6400  flat_unsigned_receive_packed_data[iflat_packed];
6401  // Get the boundary coordinates
6402  Vector<double> zeta(1);
6403  zeta[0] = flat_double_receive_packed_data[iflat_packed];
6404 
6405  // Get the halo node
6406  Node* halo_face_node_pt = this->halo_node_pt(ip, halo_id);
6407 
6408  // It could be possible that the node has been already
6409  // established boundary coordinates since it is a halo face
6410  // node. However, for those elements not on the boundary, but
6411  // having a corner node on the boundary this procedure will
6412  // establish boundary coordinates for those nodes
6413 
6414  //this->add_boundary_node(b, halo_face_node_pt);
6415 
6416  // Establish the boundary coordinates
6417  halo_face_node_pt->set_coordinates_on_boundary(b, zeta);
6418  } // for (iflat_packed < nflat_unsigned_receive)
6419  } // if (ip != my_rank)
6420  } // for (ip < nproc)
6421 
6422  // Clean all the created face elements
6423  for (unsigned ie = 0; ie < nbound_ele; ie++)
6424  {
6425  delete tmp_face_ele_pt[ie];
6426  tmp_face_ele_pt[ie] = 0;
6427  }
6428 
6429  // Now get a new face mesh representation and fill the data for those
6430  // processors with halo segments
6431  if (is_internal_boundary)
6432  {
6433  re_scale_re_assigned_initial_zeta_values_for_internal_boundary(b);
6434  }
6435 
6436  }
6437 
6438  //======================================================================
6439  /// \short Re-assign the boundary segments initial zeta (arclength)
6440  /// for those internal boundaries that were splited during the
6441  /// distribution process (only apply for internal boundaries that
6442  /// have one face element at each side of the boundary)
6443  //======================================================================
6444  template<class ELEMENT>
6447  const unsigned& b)
6448  {
6449  // ------------------------------------------------------------------
6450  // First: Get the face elements associated with the current boundary
6451  // Only include nonhalo face elements
6452  // ------------------------------------------------------------------
6453  // Temporary storage for face elements
6454  Vector<FiniteElement*> face_el_pt;
6455 
6456  // Temporary storage for the number of elements adjacent to the
6457  // boundary
6458  unsigned nele = 0;
6459 
6460  // Temporary storage for elements adjacent to the boundary that have
6461  // a common edge (related with internal boundaries)
6462  unsigned n_repeated_ele = 0;
6463 
6464  const unsigned n_regions = this->nregion();
6465 
6466  // Temporary storage for already done nodes
6467  Vector<std::pair<Node*, Node*> > done_nodes_pt;
6468 
6469  // If there is more than one region then only use boundary
6470  // coordinates from the bulk side (region 0)
6471  if (n_regions > 1)
6472  {
6473  for (unsigned rr = 0 ; rr < n_regions; rr++)
6474  {
6475  const unsigned region_id =
6476  static_cast<unsigned>(this->Region_attribute[rr]);
6477 
6478  // Loop over all elements on boundaries in region i_r
6479  const unsigned nel_in_region =
6480  this->nboundary_element_in_region(b, region_id);
6481 
6482  unsigned nel_repetead_in_region = 0;
6483 
6484  // Only bother to do anything else, if there are elements
6485  // associated with the boundary and the current region
6486  if (nel_in_region > 0)
6487  {
6488  bool repeated = false;
6489 
6490  // Loop over the bulk elements adjacent to boundary b
6491  for (unsigned e = 0; e < nel_in_region; e++)
6492  {
6493  // Get pointer to the bulk element that is adjacent to
6494  // boundary b
6495  FiniteElement* bulk_elem_pt =
6496  this->boundary_element_in_region_pt(b, region_id, e);
6497 
6498  // Remember only to work with nonhalo elements
6499  if (bulk_elem_pt->is_halo())
6500  {
6501  n_repeated_ele++;
6502  continue;
6503  }
6504 
6505  // Find the index of the face of element e along boundary b
6506  int face_index =
6507  this->face_index_at_boundary_in_region(b,region_id,e);
6508 
6509  // Before adding the new element we need to be sure that the
6510  // edge that this element represent has not been already
6511  // added
6512  FiniteElement* tmp_ele_pt =
6513  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
6514 
6515  const unsigned n_nodes = tmp_ele_pt->nnode();
6516 
6517  std::pair<Node*, Node*> tmp_pair =
6518  std::make_pair(tmp_ele_pt->node_pt(0),
6519  tmp_ele_pt->node_pt(n_nodes - 1));
6520 
6521  std::pair<Node*, Node*> tmp_pair_inverse =
6522  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
6523  tmp_ele_pt->node_pt(0));
6524 
6525  // Search for repeated nodes
6526  const unsigned n_done_nodes = done_nodes_pt.size();
6527  for (unsigned l = 0; l < n_done_nodes; l++)
6528  {
6529  if (tmp_pair == done_nodes_pt[l] ||
6530  tmp_pair_inverse == done_nodes_pt[l])
6531  {
6532  nel_repetead_in_region++;
6533  repeated = true;
6534  break;
6535  }
6536  }
6537 
6538  // Create new face element
6539  if (!repeated)
6540  {
6541  // Add the pair of nodes (edge) to the node dones
6542  done_nodes_pt.push_back(tmp_pair);
6543  // Add the element to the face elements
6544  face_el_pt.push_back(tmp_ele_pt);
6545  }
6546  else
6547  {
6548  // Clean up
6549  delete tmp_ele_pt;
6550  tmp_ele_pt = 0;
6551  }
6552 
6553  // Re-start
6554  repeated = false;
6555 
6556  } // for nel
6557 
6558  nele += nel_in_region;
6559 
6560  n_repeated_ele += nel_repetead_in_region;
6561 
6562  } // if (nel_in_region > 0)
6563  } // for (rr < n_regions)
6564  } // if (n_regions > 1)
6565  //Otherwise it's just the normal boundary functions
6566  else
6567  {
6568  // Loop over all elements on boundaries
6569  nele = this->nboundary_element(b);
6570 
6571  //Only bother to do anything else, if there are elements
6572  if (nele > 0)
6573  {
6574  // Check for repeated ones
6575  bool repeated = false;
6576 
6577  // Loop over the bulk elements adjacent to boundary b
6578  for (unsigned e = 0; e < nele; e++)
6579  {
6580  // Get pointer to the bulk element that is adjacent to
6581  // boundary b
6582  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
6583 
6584  // Remember only to work with nonhalo elements
6585  if (bulk_elem_pt->is_halo())
6586  {
6587  n_repeated_ele++;
6588  // Skip the halo element
6589  continue;
6590  }
6591 
6592  //Find the index of the face of element e along boundary b
6593  int face_index = this->face_index_at_boundary(b, e);
6594 
6595  // Before adding the new element we need to be sure that the
6596  // edge that this element represents has not been already
6597  // added (only applies for internal boundaries)
6598  FiniteElement* tmp_ele_pt =
6599  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
6600 
6601  const unsigned n_nodes = tmp_ele_pt->nnode();
6602 
6603  std::pair<Node*, Node*> tmp_pair =
6604  std::make_pair(tmp_ele_pt->node_pt(0),
6605  tmp_ele_pt->node_pt(n_nodes - 1));
6606 
6607  std::pair<Node*, Node*> tmp_pair_inverse =
6608  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
6609  tmp_ele_pt->node_pt(0));
6610 
6611  // Search for repeated nodes
6612  const unsigned n_done_nodes = done_nodes_pt.size();
6613  for (unsigned l = 0; l < n_done_nodes; l++)
6614  {
6615  if (tmp_pair == done_nodes_pt[l] ||
6616  tmp_pair_inverse == done_nodes_pt[l])
6617  {
6618  // Increase the number of repeated elements
6619  n_repeated_ele++;
6620  // Mark the element as repeated
6621  repeated = true;
6622  break;
6623  }
6624  }
6625 
6626  // Create new face element
6627  if (!repeated)
6628  {
6629  // Add the pair of nodes (edge) to the node dones
6630  done_nodes_pt.push_back(tmp_pair);
6631  // Add the element to the face elements
6632  face_el_pt.push_back(tmp_ele_pt);
6633  }
6634  else
6635  {
6636  // Free the repeated bulk element!!
6637  delete tmp_ele_pt;
6638  tmp_ele_pt = 0;
6639  }
6640 
6641  // Re-start
6642  repeated = false;
6643 
6644  } // for (e < nel)
6645  } // if (nel > 0)
6646 
6647  } // else (n_regions > 1)
6648 
6649  // Do not consider the repeated elements
6650  nele-= n_repeated_ele;
6651 
6652 #ifdef PARANOID
6653  if (nele!=face_el_pt.size())
6654  {
6655  std::ostringstream error_message;
6656  error_message
6657  << "The independet counting of face elements ("<<nele<<") for "
6658  << "boundary ("<<b<<") is different\n"
6659  << "from the real number of face elements in the container ("
6660  << face_el_pt.size() <<")\n";
6661  //<< "Possible memory leak\n"
6662  throw OomphLibError(error_message.str(),
6663  "TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary()",
6664  OOMPH_EXCEPTION_LOCATION);
6665  }
6666 #endif
6667 
6668  // ----------------------------------------------------------------
6669  // Second: Sort the face elements (to create segments), only
6670  // consider nonhalo elements
6671  // ----------------------------------------------------------------
6672 
6673  // Get the total number of nonhalo face elements
6674  const unsigned nnon_halo_face_elements = face_el_pt.size();
6675 
6676  // The vector of list to store the "segments" that compound the
6677  // boundary (segments may appear only in a distributed mesh)
6678  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
6679 
6680  // Number of already sorted face elements
6681  unsigned nsorted_face_elements = 0;
6682 
6683  // Keep track of who's done
6684  std::map<FiniteElement*, bool> done_el;
6685 
6686  // Keep track of which element is inverted
6687  std::map<FiniteElement*, bool> is_inverted;
6688 
6689  // Iterate until all possible segments have been created
6690  while(nsorted_face_elements < nnon_halo_face_elements)
6691  {
6692  // The ordered list of face elements (in a distributed mesh a
6693  // collection of contiguous face elements define a segment)
6694  std::list<FiniteElement*> sorted_el_pt;
6695 
6696 #ifdef PARANOID
6697  // Select an initial element for the segment
6698  bool found_initial_face_element = false;
6699 #endif
6700 
6701  FiniteElement* ele_face_pt = 0;
6702 
6703  unsigned iface = 0;
6704  for (iface = 0; iface < nele; iface++)
6705  {
6706  ele_face_pt = face_el_pt[iface];
6707  // If not done then take it as initial face element
6708  if (!done_el[ele_face_pt])
6709  {
6710 #ifdef PARANOID
6711  found_initial_face_element = true;
6712 #endif
6713  nsorted_face_elements++;
6714  iface++; // The next element number
6715  sorted_el_pt.push_back(ele_face_pt);
6716  // Mark as done
6717  done_el[ele_face_pt] = true;
6718  break;
6719  }
6720  } // for (iface < nele)
6721 
6722 #ifdef PARANOID
6723  if (!found_initial_face_element)
6724  {
6725  std::ostringstream error_message;
6726  error_message
6727  <<"Could not find an initial face element for the current segment\n";
6728  // << "----- Possible memory leak -----\n";
6729  throw OomphLibError(error_message.str(),
6730  "TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary()",
6731  OOMPH_EXCEPTION_LOCATION);
6732  }
6733 #endif
6734 
6735  // Number of nodes
6736  const unsigned nnod = ele_face_pt->nnode();
6737 
6738  // Left and rightmost nodes (the left and right nodes of the
6739  // current face element)
6740  Node* left_node_pt = ele_face_pt->node_pt(0);
6741  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
6742 
6743  // Continue iterating if a new face element has been added to the
6744  // list
6745  bool face_element_added = false;
6746 
6747  // While a new face element has been added to the set of sorted
6748  // face elements then re-iterate
6749  do
6750  {
6751  // Start from the next face element since we have already added
6752  // the previous one as the initial face element (any previous
6753  // face element had to be added on previous iterations)
6754  for (unsigned iiface = iface; iiface < nele; iiface++)
6755  {
6756  // Re-start flag
6757  face_element_added = false;
6758 
6759  // Get the candidate element
6760  ele_face_pt = face_el_pt[iiface];
6761 
6762  // Check that the candidate element has not been done
6763  if (!(done_el[ele_face_pt]))
6764  {
6765  // Get the left and right nodes of the current element
6766  Node* local_left_node_pt = ele_face_pt->node_pt(0);
6767  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
6768 
6769  // New element fits at the left of segment and is not inverted
6770  if (left_node_pt == local_right_node_pt)
6771  {
6772  left_node_pt = local_left_node_pt;
6773  sorted_el_pt.push_front(ele_face_pt);
6774  is_inverted[ele_face_pt] = false;
6775  face_element_added = true;
6776  }
6777  // New element fits at the left of segment and is inverted
6778  else if (left_node_pt == local_left_node_pt)
6779  {
6780  left_node_pt = local_right_node_pt;
6781  sorted_el_pt.push_front(ele_face_pt);
6782  is_inverted[ele_face_pt] = true;
6783  face_element_added = true;
6784  }
6785  // New element fits on the right of segment and is not inverted
6786  else if (right_node_pt == local_left_node_pt)
6787  {
6788  right_node_pt = local_right_node_pt;
6789  sorted_el_pt.push_back(ele_face_pt);
6790  is_inverted[ele_face_pt] = false;
6791  face_element_added = true;
6792  }
6793  // New element fits on the right of segment and is inverted
6794  else if (right_node_pt == local_right_node_pt)
6795  {
6796  right_node_pt = local_left_node_pt;
6797  sorted_el_pt.push_back(ele_face_pt);
6798  is_inverted[ele_face_pt] = true;
6799  face_element_added = true;
6800  }
6801 
6802  if (face_element_added)
6803  {
6804  done_el[ele_face_pt] = true;
6805  nsorted_face_elements++;
6806  break;
6807  }
6808 
6809  } // if (!(done_el[ele_face_pt]))
6810  } // for (iiface<nnon_halo_face_element)
6811  }while(face_element_added &&
6812  (nsorted_face_elements < nnon_halo_face_elements));
6813 
6814  // Store the created segment in the vector of segments
6815  segment_sorted_ele_pt.push_back(sorted_el_pt);
6816 
6817  } // while(nsorted_face_elements < nnon_halo_face_elements);
6818 
6819  // --------------------------------------------------------------
6820  // Third: We have the face elements sorted, now assign boundary
6821  // coordinates to the nodes in the segments and compute the
6822  // arclength of the segment
6823  // --------------------------------------------------------------
6824 
6825  // Vector of sets that stores the nodes of each segment based on a
6826  // lexicographically order starting from the bottom left node of
6827  // each segment
6828  Vector<std::set<Node*> > segment_all_nodes_pt;
6829 
6830  // The number of segments in this processor
6831  const unsigned nsegments = segment_sorted_ele_pt.size();
6832 
6833 #ifdef PARANOID
6834  if (nnon_halo_face_elements > 0 && nsegments == 0)
6835  {
6836  std::ostringstream error_message;
6837  error_message
6838  << "The number of segments is zero, but the number of nonhalo\n"
6839  << "elements is: (" << nnon_halo_face_elements << ")\n";
6840  throw OomphLibError(error_message.str(),
6841  "TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary()",
6842  OOMPH_EXCEPTION_LOCATION);
6843  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
6844 #endif
6845 
6846  // The arclength of each segment in the current processor
6847  Vector<double> segment_arclength(nsegments);
6848 
6849  // The initial zeta for the segment
6850  Vector<double> initial_zeta_segment(nsegments);
6851 
6852  // The final zeta for the segment
6853  Vector<double> final_zeta_segment(nsegments);
6854 
6855  // Go through all the segments and compute the LOCAL boundary
6856  // coordinates
6857  for (unsigned is = 0; is < nsegments; is++)
6858  {
6859 #ifdef PARANOID
6860  if (segment_sorted_ele_pt[is].size() == 0)
6861  {
6862  std::ostringstream error_message;
6863  error_message
6864  << "The (" << is << ")-th segment has no elements\n";
6865  throw OomphLibError(error_message.str(),
6866  "TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary()",
6867  OOMPH_EXCEPTION_LOCATION);
6868  } // if (segment_sorted_ele_pt[is].size() == 0)
6869 #endif
6870 
6871  // Get access to the first element on the segment
6872  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
6873 
6874  // Number of nodes
6875  const unsigned nnod = first_ele_pt->nnode();
6876 
6877  // Get the first node of the current segment
6878  Node *first_node_pt = first_ele_pt->node_pt(0);
6879  if (is_inverted[first_ele_pt])
6880  {
6881  first_node_pt = first_ele_pt->node_pt(nnod-1);
6882  }
6883 
6884  // Get access to the last element on the segment
6885  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
6886 
6887  // Get the last node of the current segment
6888  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
6889  if (is_inverted[last_ele_pt])
6890  {
6891  last_node_pt = last_ele_pt->node_pt(0);
6892  }
6893 
6894  // Coordinates of left node
6895  double x_left = first_node_pt->x(0);
6896  double y_left = first_node_pt->x(1);
6897 
6898  // Initialise boundary coordinate (local boundary coordinate for
6899  // boundaries with more than one segment)
6900  Vector<double> zeta(1, 0.0);
6901 
6902  // If we have associated a GeomObject then it is not necessary to
6903  // compute the arclength, only read the values from the nodes at
6904  // the edges
6905  if (this->boundary_geom_object_pt(b)!=0)
6906  {
6907  first_node_pt->get_coordinates_on_boundary(b, zeta);
6908  initial_zeta_segment[is] = zeta[0];
6909  last_node_pt->get_coordinates_on_boundary(b, zeta);
6910  final_zeta_segment[is] = zeta[0];
6911  }
6912 
6913  // Lexicographically bottom left node
6914  std::set<Node*> local_nodes_pt;
6915  local_nodes_pt.insert(first_node_pt);
6916 
6917  // Now loop over nodes in order
6918  for (std::list<FiniteElement*>::iterator it =
6919  segment_sorted_ele_pt[is].begin();
6920  it != segment_sorted_ele_pt[is].end(); it++)
6921  {
6922  // Get element
6923  FiniteElement* el_pt = *it;
6924 
6925  // Start node and increment
6926  unsigned k_nod = 1;
6927  int nod_diff = 1;
6928  if (is_inverted[el_pt])
6929  {
6930  k_nod = nnod - 2;
6931  nod_diff = -1;
6932  }
6933 
6934  // Loop over nodes
6935  for (unsigned j = 1; j < nnod; j++)
6936  {
6937  Node* nod_pt = el_pt->node_pt(k_nod);
6938  k_nod += nod_diff;
6939 
6940  // Coordinates of right node
6941  double x_right = nod_pt->x(0);
6942  double y_right = nod_pt->x(1);
6943 
6944  // Increment boundary coordinate
6945  zeta[0] += sqrt(
6946  (x_right - x_left) * (x_right - x_left) + (y_right - y_left)
6947  * (y_right - y_left));
6948 
6949  // Increment reference coordinate
6950  x_left = x_right;
6951  y_left = y_right;
6952 
6953  // Get lexicographically bottom left node but only
6954  // use vertex nodes as candidates
6955  local_nodes_pt.insert(nod_pt);
6956 
6957  } // for (j < nnod)
6958  } // iterator over the elements in the segment
6959 
6960  // Store the arclength of the segment
6961  segment_arclength[is] = zeta[0];
6962 
6963  // Add the nodes for the corresponding segment in the container
6964  segment_all_nodes_pt.push_back(local_nodes_pt);
6965 
6966  } // for (is < nsegments)
6967 
6968  // ------------------------------------------------------------------
6969  // Fourth: Now we have the segments sorted, with arclength and with
6970  // LOCAL arclength assigned to the nodes. Procced to re-scale the
6971  // coordinates on the nodes based on the arclength
6972  // ------------------------------------------------------------------
6973 
6974  // ------------------------------------------------------------------
6975  // Clear the original storages
6976  Boundary_segment_inverted[b].clear();
6977  Boundary_segment_initial_coordinate[b].clear();
6978  Boundary_segment_final_coordinate[b].clear();
6979 
6980  Boundary_segment_initial_zeta[b].clear();
6981  Boundary_segment_final_zeta[b].clear();
6982 
6983  Boundary_segment_initial_arclength[b].clear();
6984  Boundary_segment_final_arclength[b].clear();
6985 
6986  // Get the zeta values for the first and last node in the boundary
6987  Vector<double> first_node_zeta_coordinate(1,0.0);
6988  Vector<double> last_node_zeta_coordinate(1,0.0);
6989  first_node_zeta_coordinate = boundary_initial_zeta_coordinate(b);
6990  last_node_zeta_coordinate = boundary_final_zeta_coordinate(b);
6991 
6992  // Get the boundary arclength
6993  const double boundary_arclength =
6994  std::max(first_node_zeta_coordinate[0], last_node_zeta_coordinate[0]);
6995 
6996  // Go through the segments and get the first and last node for each
6997  // segment
6998  for (unsigned is = 0; is < nsegments; is++)
6999  {
7000  // Get the first face element of the segment
7001  FiniteElement* first_face_ele_pt = segment_sorted_ele_pt[is].front();
7002 
7003  // The number of nodes
7004  const unsigned nnod = first_face_ele_pt->nnode();
7005 
7006  // ... and the first node of the segment
7007  Node* first_node_pt = first_face_ele_pt->node_pt(0);
7008  if (is_inverted[first_face_ele_pt])
7009  {
7010  first_node_pt = first_face_ele_pt->node_pt(nnod-1);
7011  }
7012 
7013  // Get the bound coordinates of the node
7014  Vector<double> zeta_first(1);
7015  first_node_pt->get_coordinates_on_boundary(b, zeta_first);
7016 
7017  // Get the last face element of the segment
7018  FiniteElement* last_face_ele_pt = segment_sorted_ele_pt[is].back();
7019 
7020  // ... and the last node of the segment
7021  Node* last_node_pt = last_face_ele_pt->node_pt(nnod-1);
7022  if (is_inverted[last_face_ele_pt])
7023  {
7024  last_node_pt = last_face_ele_pt->node_pt(0);
7025  }
7026 
7027  // Get the bound coordinates of the node
7028  Vector<double> zeta_last(1);
7029  last_node_pt->get_coordinates_on_boundary(b, zeta_last);
7030 
7031  // Now that we have the first and last node of the segment, get
7032  // the coordinates of the nodes
7033  Vector<double> first_node_coord(2);
7034  Vector<double> last_node_coord(2);
7035  for (unsigned i = 0; i < 2; i++)
7036  {
7037  first_node_coord[i] = first_node_pt->x(i);
7038  last_node_coord[i] = last_node_pt->x(i);
7039  }
7040 
7041  // Re-assign the values to identify the segments on the new mesh
7042  Boundary_segment_inverted[b].push_back(0);
7043  Boundary_segment_initial_coordinate[b].push_back(first_node_coord);
7044  Boundary_segment_final_coordinate[b].push_back(last_node_coord);
7045 
7046  // Check if the boudary has an associated GeomObject
7047  if (this->boundary_geom_object_pt(b)!=0)
7048  {
7049  Boundary_segment_initial_zeta[b].push_back(zeta_first[0]);
7050  Boundary_segment_final_zeta[b].push_back(zeta_last[0]);
7051  }
7052  else
7053  {
7054  // Re-assign the values and re-scale them
7055  Boundary_segment_initial_arclength[b].push_back(
7056  zeta_first[0] * boundary_arclength);
7057  Boundary_segment_final_arclength[b].push_back(
7058  zeta_last[0] * boundary_arclength);
7059  }
7060 
7061  } // for (is < nsegments)
7062 
7063  // Clean all the created face elements
7064  for (unsigned i = 0; i < nele; i++)
7065  {
7066  delete face_el_pt[i];
7067  face_el_pt[i] = 0;
7068  }
7069 
7070  }
7071 
7072 #endif // OOMPH_HAS_MPI
7073 
7074 
7075 
7076 #ifdef OOMPH_HAS_TRIANGLE_LIB
7077 
7078  //========================================================================
7079  /// Create TriangulateIO object via the .poly file
7080  //========================================================================
7081  template <class ELEMENT>
7083  build_triangulateio(const std::string& poly_file_name,
7084  TriangulateIO& triangulate_io,
7085  bool &use_attributes)
7086  {
7087 
7088  // Process poly file
7089  // -----------------
7090  std::ifstream poly_file(poly_file_name.c_str(),std::ios_base::in);
7091  if(!poly_file)
7092  {
7093  throw OomphLibError("Error opening .poly file\n",
7094  OOMPH_CURRENT_FUNCTION,
7095  OOMPH_EXCEPTION_LOCATION);
7096  }
7097 
7098  // Initialize triangulateio structure
7100 
7101  // Ignore the first line with structure description
7102  poly_file.ignore(80,'\n');
7103 
7104  // Read and store number of nodes
7105  unsigned invertices;
7106  poly_file>>invertices;
7107  triangulate_io.numberofpoints=invertices;
7108 
7109  // Initialisation of the point list
7110  triangulate_io.pointlist =
7111  (double *) malloc(triangulate_io.numberofpoints * 2 * sizeof(double));
7112 
7113  // Read and store spatial dimension of nodes
7114  unsigned mesh_dim;
7115  poly_file>>mesh_dim;
7116 
7117  if(mesh_dim == 0)
7118  {
7119  mesh_dim=2;
7120  }
7121 
7122 #ifdef PARANOID
7123  if(mesh_dim!=2)
7124  {
7125  throw OomphLibError("The dimension must be 2\n",
7126  OOMPH_CURRENT_FUNCTION,
7127  OOMPH_EXCEPTION_LOCATION);
7128  }
7129 #endif
7130 
7131  // Read and check the flag for attributes
7132  unsigned nextras;
7133  poly_file>> nextras;
7134 
7135  triangulate_io.numberofpointattributes = 0;
7136  triangulate_io.pointattributelist = (double *) NULL;
7137 
7138  // Read and check the flag for boundary markers
7139  unsigned nodemarkers;
7140  poly_file>>nodemarkers;
7141  triangulate_io.pointmarkerlist = (int *) NULL;
7142 
7143 #ifdef PARANOID
7144  // Reading the .poly with the oomph.lib we need
7145  // to set the point attribute and markers to 0
7146  if(nextras!=0 || nodemarkers!=0)
7147  {
7148  oomph_info << "===================================================="
7149  << std::endl<<std::endl;
7150  oomph_info <<"Reading the .poly file via oomph_lib \n"
7151  <<"point's attribute and point's markers \n"
7152  <<"are automatically set to 0"<<std::endl;
7153  oomph_info << "===================================================="
7154  <<std::endl;
7155  }
7156 #endif
7157 
7158  // Dummy for node number (and attribute or markers if included)
7159  unsigned dummy_value;
7160  unsigned count_point=0;
7161  std::string test_string;
7162 
7163  // Skip line with commentary
7164  getline(poly_file,test_string,'#');
7165  poly_file.ignore(80,'\n');
7166 
7167  // Read and store all the nodes coordinates
7168  // (hole's vertices as well)
7169  for(unsigned count=0;count<invertices;count++)
7170  {
7171  poly_file>>dummy_value;
7172  poly_file>>triangulate_io.pointlist[count_point];
7173  poly_file>>triangulate_io.pointlist[count_point+1];
7174  if(nextras!=0 || nodemarkers!=0)
7175  {
7176  for(unsigned j=0;j<nextras;j++)
7177  {
7178  poly_file>>dummy_value;
7179  }
7180  }
7181  else if(nextras!=0 && nodemarkers!=0)
7182  {
7183  for(unsigned j=0;j<nextras;j++)
7184  {
7185  poly_file>>dummy_value;
7186  poly_file>>dummy_value;
7187  }
7188  }
7189  // Read the next line
7190  poly_file.ignore(80,'\n');
7191 
7192  // Skip line with commentary for internal box whether found
7193  if(poly_file.get() == '#')
7194  {
7195  poly_file.ignore(80,'\n');
7196  }
7197  // If read the char should be put back in the string
7198 
7199  else
7200  {
7201  poly_file.unget();
7202  }
7203  count_point+=2;
7204  }
7205 
7206  // The line with the segment's commentary has been skipped
7207  // by the command of the last loop
7208 
7209  // Read and store the number of segments
7210  unsigned dummy_seg;
7211  unsigned inelements;
7212  poly_file>>inelements;
7213 
7214  unsigned segment_markers;
7215  poly_file>>segment_markers;
7216 
7217  // Marker list should be provided by the user to assign
7218  // each segment to a boundary
7219 #ifdef PARANOID
7220  if(segment_markers!=1)
7221  {
7222 
7223  std::ostringstream error_stream;
7224  error_stream
7225  <<"The segment marker should be provided \n"
7226  <<"In order to assign each segment to a boundary \n "<< std::endl;
7227 
7228  throw OomphLibError(error_stream.str(),
7229  OOMPH_CURRENT_FUNCTION,
7230  OOMPH_EXCEPTION_LOCATION);
7231  }
7232 #endif
7233 
7234  triangulate_io.numberofsegments = inelements;
7235  triangulate_io.segmentlist =
7236  (int *) malloc(triangulate_io.numberofsegments * 2 * sizeof(int));
7237  triangulate_io.segmentmarkerlist =
7238  (int *) malloc(triangulate_io.numberofsegments * sizeof(int));
7239 
7240  // Read all the segments edges and markers
7241  for(unsigned i=0;i<2*inelements;i+=2)
7242  {
7243  poly_file>>dummy_seg;
7244  poly_file>>triangulate_io.segmentlist[i];
7245  poly_file>>triangulate_io.segmentlist[i+1];
7246  if(segment_markers!=0)
7247  {
7248  poly_file>>triangulate_io.segmentmarkerlist[i/2];
7249  }
7250 
7251  //Skip line with commentary
7252  poly_file.ignore(80,'\n');
7253  }
7254 
7255  // Read and store the number of holes if given
7256  // Skip line with commentary
7257  if(getline(poly_file,test_string,'#'))
7258  {
7259  poly_file.ignore(80,'\n');
7260 
7261  unsigned dummy_hole;
7262  unsigned nhole;
7263  poly_file>>nhole;
7264 
7265  triangulate_io.numberofholes = nhole;
7266  triangulate_io.holelist =
7267  (double *) malloc(triangulate_io.numberofholes * 2 * sizeof(double));
7268 
7269  // Loop over the holes to get centre coords and store value onto the
7270  // TriangulateIO object
7271  for(unsigned i=0;i<2*nhole;i+=2)
7272  {
7273  poly_file>>dummy_hole;
7274  poly_file>>triangulate_io.holelist[i];
7275  poly_file>>triangulate_io.holelist[i+1];
7276  }
7277  }
7278 
7279  // Read and store the number of regions if given
7280  // Skip line with commentary
7281  if(getline(poly_file,test_string,'#'))
7282  {
7283  poly_file.ignore(80,'\n');
7284 
7285  unsigned dummy_region;
7286  unsigned nregion;
7287  poly_file>>nregion;
7288  std::cerr << "Regions: "<< nregion << std::endl;
7289  getchar();
7290 
7291  triangulate_io.numberofregions = nregion;
7292  triangulate_io.regionlist =
7293  (double *) malloc(triangulate_io.numberofregions * 4 * sizeof(double));
7294 
7295  // Check for using regions
7296  if (nregion > 0)
7297  {use_attributes=true;}
7298 
7299  // Loop over the regions to get coords and store value onto the
7300  // TriangulateIO object
7301  for(unsigned i=0;i<nregion;i++)
7302  {
7303  poly_file>>dummy_region;
7304  poly_file>>triangulate_io.regionlist[4*i];
7305  poly_file>>triangulate_io.regionlist[4*i+1];
7306  poly_file>>triangulate_io.regionlist[4*i+2];
7307  triangulate_io.regionlist[4*i+3] = 0.0;
7308  }
7309  }
7310 
7311  }
7312 
7313 #endif
7314 
7315 #ifdef OOMPH_HAS_TRIANGLE_LIB
7316 #ifdef OOMPH_HAS_MPI
7317 
7318  //======================================================================
7319  /// Used to dump info. related with distributed triangle meshes
7320  //======================================================================
7321  template<class ELEMENT>
7323  dump_distributed_info_for_restart(std::ostream &dump_file)
7324  {
7325  // First check that the mesh is distributed
7326  if (this->is_mesh_distributed())
7327  {
7328  // Save the original number of boundaries
7329  const unsigned nboundary = this->nboundary();
7330  dump_file << nboundary
7331  << " # number of original boundaries" << std::endl;
7332 
7333  // Save the number of shared boundaries
7334  const unsigned nshared_boundaries = this->nshared_boundaries();
7335  dump_file << nshared_boundaries
7336  << " # number of shared boundaries" << std::endl;
7337 
7338  // Save the initial and final shared boundaries ids
7339  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
7340  dump_file << init_shd_bnd_id
7341  << " # initial shared boundaries id" << std::endl;
7342 
7343  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
7344  dump_file << final_shd_bnd_id
7345  << " # final shared boundaries id" << std::endl;
7346 
7347  // Save the number of processors
7348  const unsigned nprocs = this->shared_boundaries_ids().size();
7349  dump_file << nprocs << " # number of processors" << std::endl;
7350 
7351  // Now save the processors ids and the shared boundary created
7352  // by them
7353  for (unsigned ip = 0; ip < nprocs; ip++)
7354  {
7355  for (unsigned jp = 0; jp < nprocs; jp++)
7356  {
7357  if (ip != jp)
7358  {
7359  // Get the number of shared boundaries with it these two
7360  // processors
7361  const unsigned nshared_boundaries_iproc_jproc =
7362  this->shared_boundaries_ids(ip, jp).size();
7363 
7364  // Save the number of shared boundaries with in these two
7365  // processors
7366  dump_file << nshared_boundaries_iproc_jproc
7367  << " # number of shared boundaries with in two "
7368  << "processors" << std::endl;
7369  for (unsigned is = 0; is < nshared_boundaries_iproc_jproc; is++)
7370  {
7371  const unsigned shared_boundary_id =
7372  this->shared_boundaries_ids(ip, jp, is);
7373  dump_file << ip << " " << jp << " " << shared_boundary_id
7374  << " # ip jp shared_boundary of processors ip and jp"
7375  << std::endl;
7376 
7377  } // for (is < nshared_boundaries_iproc_jproc)
7378  }
7379  } // for (jp < nprocs)
7380  } // for (ip < nprocs)
7381 
7382  // Now save the info. that states which shared boundary overlaps
7383  // an internal boundary
7384 
7385  // First check if there are shared boundaries overlapping internal
7386  // boundaries
7387  const unsigned nshared_boundaries_overlap_internal_boundaries =
7388  this->nshared_boundary_overlaps_internal_boundary();
7389  dump_file << nshared_boundaries_overlap_internal_boundaries
7390  << " # number of shared boundaries that overlap internal "
7391  << "boundaries" << std::endl;
7392 
7393  if (nshared_boundaries_overlap_internal_boundaries > 0)
7394  {
7395  for (unsigned isb = init_shd_bnd_id; isb < final_shd_bnd_id; isb++)
7396  {
7397  // Check if the current shared boundary overlaps an internal
7398  // boundary
7399  if (this->shared_boundary_overlaps_internal_boundary(isb))
7400  {
7401  // Which internal boundary is overlapped by the shared
7402  // boundary
7403  const unsigned overlapped_internal_boundary =
7404  shared_boundary_overlapping_internal_boundary(isb);
7405  // Save the shared boundary that overlaps the internal boundary
7406  dump_file << isb << " " << overlapped_internal_boundary
7407  << " # the shared boundary overlaps the internal "
7408  << "boundary " << std::endl;
7409 
7410  } // if (this->shared_boundary_overlaps_internal_boundary(isb))
7411  } // for (isb < final_shd_bnd_id)
7412  } // if (nshared_boundaries_overlap_internal_boundaries > 0)
7413 
7414  // Now save the info. related with the initial and final
7415  // boundary coordinates for each original boundary
7416 
7417  // Go through all the (original) boundaries to update the initial
7418  // and final boundary coordinates
7419  for (unsigned b = 0; b < nboundary; b++)
7420  {
7421  // Check if the boundary zeta coordinates for this boundary have
7422  // been already assigned, if that is the case then state the
7423  // flag to know that info. should be read
7424  if (Assigned_segments_initial_zeta_values[b])
7425  {
7426  // The boundary coordinates have been computed then state
7427  // the flag and save the info.
7428  dump_file << "1 # assigned boundary coordinates initial zeta values"
7429  << std::endl;
7430 
7431  // Save the initial and final boundary coordinates, same as
7432  // the initial and final zeta values for each boundary
7433 
7434  // First the vertices coordinates
7435  Vector<double> initial_coordinates=this->boundary_initial_coordinate(b);
7436 
7437  Vector<double> final_coordinates=this->boundary_final_coordinate(b);
7438 
7439  dump_file << std::setprecision(14)
7440  << initial_coordinates[0] << " " << initial_coordinates[1]
7441  << " # initial coordinates for the current boundary"
7442  << std::endl;
7443 
7444  dump_file << std::setprecision(14)
7445  << final_coordinates[0] << " " << final_coordinates[1]
7446  << " # final coordinates for the current boundary"
7447  << std::endl;
7448 
7449  // ... then the zeta values
7450 
7451 #ifdef PARANOID
7452  // Get the number of zeta coordinates (should be one)
7453  const unsigned zeta_size =
7454  this->boundary_initial_zeta_coordinate(b).size();
7455 
7456  if (zeta_size != 1)
7457  {
7458  std::ostringstream error_message;
7459  error_message
7460  <<"The dimension for the zeta values container is different\n"
7461  << "from 1, the current implementation only supports\n"
7462  << "one-dimensioned zeta containers\n\n";
7463  throw OomphLibError(error_message.str(),
7464  "TriangleMesh::dump_distributed_info_for_restart()",
7465  OOMPH_EXCEPTION_LOCATION);
7466  }
7467 #endif
7468 
7469  Vector<double> zeta_initial = this->boundary_initial_zeta_coordinate(b);
7470  Vector<double> zeta_final = this->boundary_final_zeta_coordinate(b);
7471 
7472  dump_file << std::setprecision(14)
7473  << zeta_initial[0]
7474  << " # initial zeta value for the current boundary"
7475  << std::endl;
7476 
7477  dump_file << std::setprecision(14)
7478  << zeta_final[0]
7479  << " # final zeta value for the current boundary"
7480  << std::endl;
7481 
7482  // Get the number of segments of the current boundary
7483  const unsigned nsegments = this->nboundary_segment(b);
7484  // Save the number of segments of the current boundary
7485  dump_file << b << " " << nsegments
7486  << " # of segments for the current boundary"
7487  << std::endl;
7488 
7489  // ... and then save that info for each segments
7490  for (unsigned is = 0; is < nsegments; is++)
7491  {
7492  // First the vertices coordinates
7493  Vector<double> initial_segment_coordinates =
7494  this->boundary_segment_initial_coordinate(b)[is];
7495  Vector<double> final_segment_coordinates =
7496  this->boundary_segment_final_coordinate(b)[is];
7497 
7498  dump_file << std::setprecision(14)
7499  << initial_segment_coordinates[0] << " "
7500  << initial_segment_coordinates[1]
7501  << " # initial segment coordinates for the current boundary"
7502  << std::endl;
7503 
7504  dump_file << std::setprecision(14)
7505  << final_segment_coordinates[0] << " "
7506  << final_segment_coordinates[1]
7507  << " # final segment coordinates for the current boundary"
7508  << std::endl;
7509 
7510  // ... then the zeta values
7511 
7512  if (this->boundary_geom_object_pt(b)!=0)
7513  {
7514  const double zeta_segment_initial =
7515  this->boundary_segment_initial_zeta(b)[is];
7516  const double zeta_segment_final =
7517  this->boundary_segment_final_zeta(b)[is];
7518 
7519  dump_file << std::setprecision(14)
7520  << zeta_segment_initial
7521  << " # initial segment zeta value for the current boundary"
7522  << std::endl;
7523 
7524  dump_file << std::setprecision(14)
7525  << zeta_segment_final
7526  << " # final segment zeta value for the current boundary"
7527  << std::endl;
7528  }
7529  else
7530  {
7531  const double arclength_segment_initial =
7532  this->boundary_segment_initial_arclength(b)[is];
7533  const double arclength_segment_final =
7534  this->boundary_segment_final_arclength(b)[is];
7535 
7536  dump_file << std::setprecision(14)
7537  << arclength_segment_initial
7538  << " # initial segment arclength for the current boundary"
7539  << std::endl;
7540 
7541  dump_file << std::setprecision(14)
7542  << arclength_segment_final
7543  << " # final segment arclength for the current boundary"
7544  << std::endl;
7545 
7546  } // else if (this->boundary_geom_object_pt(b)!=0)
7547 
7548  } // for (is < nsegments)
7549 
7550  } // if (Assigned_segments_initial_zeta_values[b])
7551  else
7552  {
7553  // The boundary coordinates have NOT been computed then state
7554  // the flag and save the info.
7555  dump_file << "0 # assigned boundary coordinates initial zeta values"
7556  << std::endl;
7557  }
7558 
7559  } // for (b < nboundary)
7560 
7561  } // if (this->is_mesh_distributed())
7562 
7563  }
7564 
7565  //======================================================================
7566  /// Used to read info. related with distributed triangle meshes
7567  //======================================================================
7568  template<class ELEMENT>
7570  read_distributed_info_for_restart(std::istream &restart_file)
7571  {
7572  // First check that the mesh is distributed
7573  if (this->is_mesh_distributed())
7574  {
7575  // Read the number of original boundaries
7576  const unsigned n_boundary = read_unsigned_line_helper(restart_file);
7577 
7578 #ifdef PARANOID
7579  if (n_boundary != this->nboundary())
7580  {
7581  std::ostringstream error_message;
7582  error_message
7583  << "The number of boundaries (" << n_boundary << ") on the "
7584  << "file used for restarting is different\nfrom the number of "
7585  << "boundaries ("<< this->nboundary() << ") on the current "
7586  << "mesh!!!\n\n\n";
7587  throw OomphLibError(error_message.str(),
7588  "TriangleMesh::read_distributed_info_for_restart()",
7589  OOMPH_EXCEPTION_LOCATION);
7590  }
7591 #endif
7592 
7593  // Read the number of shared boundaries
7594  unsigned n_shared_boundaries =
7595  read_unsigned_line_helper(restart_file);
7596  // We need to read the data because it comes in the file (add and
7597  // substract to avoid compilation warning)
7598  n_shared_boundaries++;
7599  n_shared_boundaries--;
7600 
7601  // Read the initial and final shared boundaries ids
7602  unsigned init_shd_bnd_id = read_unsigned_line_helper(restart_file);
7603  // We need to read the data because it comes in the file (add and
7604  // substract to avoid compilation warning)
7605  init_shd_bnd_id++;
7606  init_shd_bnd_id--;
7607  // Add and substract to avoid compilation warning
7608  unsigned final_shd_bnd_id = read_unsigned_line_helper(restart_file);
7609  // We need to read the data because it comes in the file (add and
7610  // substract to avoid compilation warning)
7611  final_shd_bnd_id++;
7612  final_shd_bnd_id--;
7613 
7614  // Read the number of processors involved in the generation of
7615  // mesh before restart
7616  const unsigned n_procs = read_unsigned_line_helper(restart_file);
7617 
7618 #ifdef PARANOID
7619  if (static_cast<int>(n_procs) != this->communicator_pt()->nproc())
7620  {
7621  std::ostringstream error_message;
7622  error_message
7623  << "The number of previously used processors ("<< n_procs
7624  << ") (read from the restart file) is different\nfrom the "
7625  << "number of current used processors ("
7626  << this->communicator_pt()->nproc() << ")\n\n";
7627  throw OomphLibError(error_message.str(),
7628  "TriangleMesh::read_distributed_info_for_restart()",
7629  OOMPH_EXCEPTION_LOCATION);
7630  }
7631 #endif
7632 
7633  // Clear all previuos info. related with shared boundaries
7634  this->shared_boundaries_ids().clear();
7635  this->shared_boundary_from_processors().clear();
7636  this->shared_boundary_overlaps_internal_boundary().clear();
7637 
7638  // Create the storage for the shared boundaries ids related with
7639  // the processors
7640  this->shared_boundaries_ids().resize(n_procs);
7641 
7642  // Now read the processors ids and the shared boundary created
7643  // by them
7644  for (unsigned ip = 0; ip < n_procs; ip++)
7645  {
7646  // Create the storage for the shared boundaries ids related with
7647  // the processors
7648  this->shared_boundaries_ids(ip).resize(n_procs);
7649  for (unsigned jp = 0; jp < n_procs; jp++)
7650  {
7651  if (ip != jp)
7652  {
7653  // Read the number of shared boundaries with in these two
7654  // processors
7655  const unsigned nshared_boundaries_iproc_jproc =
7656  read_unsigned_line_helper(restart_file);
7657  for (unsigned is = 0; is < nshared_boundaries_iproc_jproc; is++)
7658  {
7659  // Get the processors
7660  unsigned tmp_ip;
7661  restart_file >> tmp_ip;
7662  unsigned tmp_jp;
7663  restart_file >> tmp_jp;
7664 
7665  // Get the shared boundary id created by these two
7666  // processors
7667  const unsigned shared_boundary_id =
7668  read_unsigned_line_helper(restart_file);
7669 
7670  // Update the info. of the processors that give rise to
7671  // the shared boundaries
7672  this->shared_boundaries_ids(ip, jp).
7673  push_back(shared_boundary_id);
7674 
7675  // Update the structure that states the processors that
7676  // gave rise to the shared boundary
7677  Vector<unsigned> processors(2);
7678  processors[0] = ip;
7679  processors[1] = jp;
7680  this->shared_boundary_from_processors()[shared_boundary_id] =
7681  processors;
7682 
7683  } // for (is < nshared_boundaries_iproc_jproc)
7684  }
7685  } // for (jp < n_procs)
7686  } // for (ip < n_procs)
7687 
7688  // Now read the info. that states which shared boundary overlaps
7689  // an internal boundary
7690 
7691  // First check if there are shared boundaries overlapping internal
7692  // boundaries
7693  const unsigned nshared_boundaries_overlap_internal_boundaries =
7694  read_unsigned_line_helper(restart_file);
7695 
7696  for (unsigned isb = 0;
7697  isb < nshared_boundaries_overlap_internal_boundaries;
7698  isb++)
7699  {
7700  // Read the shared boundary that overlaps an internal boundary
7701  unsigned shared_boundary_overlapping;
7702  restart_file >> shared_boundary_overlapping;
7703  // ... and read the internal boundary that overlaps
7704  const unsigned overlapped_internal_boundary =
7705  read_unsigned_line_helper(restart_file);
7706 
7707  // Re-establish the info. of the shared boundaries overlapped
7708  // by internal boundaries
7709  this->shared_boundary_overlaps_internal_boundary()
7710  [shared_boundary_overlapping] = overlapped_internal_boundary;
7711  } // for (isb < nshared_boundaries_overlap_internal_boundaries)
7712 
7713  // Now read the info. related with the initial and final
7714  // boundary coordinates for each original boundary
7715 
7716  // Go through all the (original) boundaries to update the initial
7717  // and final boundary coordinates
7718  for (unsigned b = 0; b < n_boundary; b++)
7719  {
7720  // For each boundary check if the boundary coordinates initial
7721  // and final zeta vales were assigned in the restart file
7722  const unsigned boundary_coordinates_initial_zeta_values_assigned =
7723  read_unsigned_line_helper(restart_file);
7724 
7725  if (boundary_coordinates_initial_zeta_values_assigned)
7726  {
7727  // Clear any previous stored info. There should not be
7728  // info. already stored but better clear the info. for the
7729  // boundary
7730  Boundary_initial_coordinate[b].clear();
7731  Boundary_final_coordinate[b].clear();
7732 
7733  Boundary_initial_zeta_coordinate[b].clear();
7734  Boundary_final_zeta_coordinate[b].clear();
7735 
7736  // The info. for the segments
7737  Boundary_segment_inverted[b].clear();
7738  Boundary_segment_initial_coordinate[b].clear();
7739  Boundary_segment_final_coordinate[b].clear();
7740 
7741  Boundary_segment_initial_zeta[b].clear();
7742  Boundary_segment_final_zeta[b].clear();
7743 
7744  Boundary_segment_initial_arclength[b].clear();
7745  Boundary_segment_final_arclength[b].clear();
7746 
7747  // Read the initial and final boundary coordinates, same as
7748  // the initial and final zeta values for each boundary
7749 
7750  // First the vertices coordinates
7751  Vector<double> initial_coordinates(2);
7752 
7753  // Read the initial coordinates
7754  restart_file >> initial_coordinates[0] >> initial_coordinates[1];
7755 
7756  // Ignore rest of line
7757  restart_file.ignore(80,'\n');
7758 
7759  Vector<double> final_coordinates(2);
7760 
7761  // Read the final coordinates
7762  restart_file >> final_coordinates[0] >> final_coordinates[1];
7763 
7764  // Ignore rest of line
7765  restart_file.ignore(80,'\n');
7766 
7767  // Set the values in the containers
7768 
7769 
7770  this->boundary_initial_coordinate(b)=initial_coordinates;
7771  this->boundary_final_coordinate(b)=final_coordinates;
7772 
7773  // ... now read the zeta values
7774  Vector<double> zeta_initial(1);
7775  restart_file >> zeta_initial[0];
7776 
7777  // Ignore rest of line
7778  restart_file.ignore(80,'\n');
7779 
7780  Vector<double> zeta_final(1);
7781  restart_file >> zeta_final[0];
7782 
7783  // Ignore rest of line
7784  restart_file.ignore(80,'\n');
7785 
7786  // Set the values in the containers
7787  this->boundary_initial_zeta_coordinate(b) = zeta_initial;
7788  this->boundary_final_zeta_coordinate(b) = zeta_final;
7789 
7790  // Get the curent boundary id from the restart file
7791  unsigned current_boundary;
7792  restart_file >> current_boundary;
7793 
7794 #ifdef PARANOID
7795  if (current_boundary != b)
7796  {
7797  std::ostringstream error_message;
7798  error_message
7799  << "The current boundary id from the restart file ("
7800  << current_boundary << ") is different from\nthe boundary id "
7801  << b << "currently used to re-establish the initial and\nfinal "
7802  << "segment's zeta values\n\n";
7803  throw OomphLibError(error_message.str(),
7804  "TriangleMesh::read_distributed_info_for_restart()",
7805  OOMPH_EXCEPTION_LOCATION);
7806  }
7807 #endif
7808 
7809  // ... and its number of segments
7810  unsigned nsegments;
7811  restart_file >> nsegments;
7812 
7813  // Ignore rest of line
7814  restart_file.ignore(80,'\n');
7815 
7816  // Now read all the segments info.
7817 
7818  // ... and then save that info for each segments
7819  for (unsigned is = 0; is < nsegments; is++)
7820  {
7821  // First the vertices coordinates
7822  Vector<double> initial_segment_coordinates(2);
7823 
7824  // Read the initial coordinates
7825  restart_file >> initial_segment_coordinates[0]
7826  >> initial_segment_coordinates[1];
7827 
7828  // Ignore rest of line
7829  restart_file.ignore(80,'\n');
7830 
7831  Vector<double> final_segment_coordinates(2);
7832 
7833  // Read the final coordinates
7834  restart_file >> final_segment_coordinates[0]
7835  >> final_segment_coordinates[1];
7836 
7837  // Ignore rest of line
7838  restart_file.ignore(80,'\n');
7839 
7840  // Set the values in the containers
7841  this->boundary_segment_initial_coordinate(b).push_back(
7842  initial_segment_coordinates);
7843  this->boundary_segment_final_coordinate(b).push_back(
7844  final_segment_coordinates);
7845 
7846  // ... then the zeta values for the segment
7847  if (this->boundary_geom_object_pt(b)!=0)
7848  {
7849  Vector<double> zeta_segment_initial(1);
7850  restart_file >> zeta_segment_initial[0];
7851 
7852  // Ignore rest of line
7853  restart_file.ignore(80,'\n');
7854 
7855  Vector<double> zeta_segment_final(1);
7856  restart_file >> zeta_segment_final[0];
7857 
7858  // Ignore rest of line
7859  restart_file.ignore(80,'\n');
7860 
7861  // Set the values in the containers for the segment
7862  this->boundary_segment_initial_zeta(b).push_back(
7863  zeta_segment_initial[0]);
7864  this->boundary_segment_final_zeta(b).push_back(
7865  zeta_segment_final[0]);
7866  }
7867  else
7868  {
7869  Vector<double> arclength_segment_initial(1);
7870  restart_file >> arclength_segment_initial[0];
7871 
7872  // Ignore rest of line
7873  restart_file.ignore(80,'\n');
7874 
7875  Vector<double> arclength_segment_final(1);
7876  restart_file >> arclength_segment_final[0];
7877 
7878  // Ignore rest of line
7879  restart_file.ignore(80,'\n');
7880 
7881  // Set the values in the containers for the segment
7882  this->boundary_segment_initial_arclength(b).push_back(
7883  arclength_segment_initial[0]);
7884  this->boundary_segment_final_arclength(b).push_back(
7885  arclength_segment_final[0]);
7886  } // else if (this->boundary_geom_object_pt(b)!=0)
7887 
7888  } // for (is < nsegments)
7889 
7890  } // if (boundary_coordinates_initial_zeta_values_assigned)
7891 
7892  } // for (b < n_boundary)
7893 
7894  } // if (this->is_mesh_distributed())
7895 
7896  }
7897 
7898 #endif // #ifdef OOMPH_HAS_MPI
7899 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
7900 
7901  //===================================================================
7902  // Output the nodes on the boundaries and their / respective boundary
7903  // coordinates(into separate tecplot / zones)
7904  //===================================================================
7905  template<class ELEMENT>
7907  std::ostream &outfile)
7908  {
7909  // First get all the elements adjacent to the given boundary, then
7910  // the face elements and extract the nodes on the boundaries using
7911  // the face elements. We can not use the data structure
7912  // Boundary_node_pt since the multi_domain functions add nodes there
7913  // without assigning the required boundary coordinate
7914 
7915  // Store the nodes in a set so we do not have repeated nodes
7916  std::set<Node*> boundary_nodes_pt;
7917  const unsigned n_boundary_ele = this->nboundary_element(b);
7918  for (unsigned e = 0; e < n_boundary_ele; e++)
7919  {
7920  // Get the boundary bulk element
7921  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
7922 #ifdef OOMPH_HAS_MPI
7923  // Only work with nonhalo elements if the mesh is distributed
7924  if (!bulk_ele_pt->is_halo())
7925  {
7926 #endif
7927  // Get the face index
7928  int face_index = this->face_index_at_boundary(b, e);
7929  // Create the face element
7930  FiniteElement* face_ele_pt = new DummyFaceElement<ELEMENT> (
7931  bulk_ele_pt, face_index);
7932 
7933  // Get the number of nodes on the face element
7934  const unsigned n_nodes = face_ele_pt->nnode();
7935  for (unsigned i = 0; i < n_nodes; i++)
7936  {
7937  // Get the nodes in the face elements
7938  Node* tmp_node_pt = face_ele_pt->node_pt(i);
7939  // Add the nodes to the set of boundary nodes
7940  boundary_nodes_pt.insert(tmp_node_pt);
7941  } // for (i < n_nodes)
7942 
7943  // Free the memory allocated for the face element
7944  delete face_ele_pt;
7945  face_ele_pt = 0;
7946 #ifdef OOMPH_HAS_MPI
7947  } // if (!bulk_ele_pt->is_halo())
7948 #endif
7949 
7950  } // for (e < n_boundary_ele)
7951 
7952  outfile << "ZONE T=\"Boundary nodes" << b << "\"\n";
7953  // Set to store the boundary nodes in order
7954  std::set<Vector<double> > set_node_coord;
7955  // Loop over the nodes on the boundary and store them in the set
7956  for (std::set<Node*>::iterator it = boundary_nodes_pt.begin();
7957  it != boundary_nodes_pt.end(); it++)
7958  {
7959  Node *inode_pt = (*it);
7960 
7961  // Get the node coordinates
7962  const unsigned n_dim = inode_pt->ndim();
7963  Vector<double> node_coord(n_dim+1);
7964 
7965  // Get the boundary coordinate
7966  Vector<double> zeta(1);
7967  inode_pt->get_coordinates_on_boundary(b, zeta);
7968  node_coord[0] = zeta[0];
7969  for (unsigned j = 0; j < n_dim; j++)
7970  {
7971  node_coord[j+1] = inode_pt->x(j);
7972  }
7973  set_node_coord.insert(node_coord);
7974  }
7975 
7976  for (std::set<Vector<double> >::iterator it = set_node_coord.begin();
7977  it != set_node_coord.end(); it++)
7978  {
7979  // Get the node coordinates
7980  Vector<double> node_coord = (*it);
7981 
7982  // Output the node coordinates
7983  const unsigned n_dim = node_coord.size()-1;
7984  for (unsigned j = 0; j < n_dim; j++)
7985  {
7986  outfile << node_coord[j+1] << " ";
7987  }
7988  // ... add an extra coordinate to avoid error with tecplot
7989  outfile << "0.0" << std::endl;
7990  }
7991 
7992  // ... loop again to plot the bound coordinates
7993  outfile << "ZONE T=\"Boundary coordinates " << b << "\"\n";
7994  for (std::set<Vector<double> >::iterator it = set_node_coord.begin();
7995  it != set_node_coord.end(); it++)
7996  {
7997  // Get the node coordinates
7998  Vector<double> node_coord = (*it);
7999 
8000  // Output the node coordinates
8001  const unsigned n_dim = node_coord.size()-1;
8002  for (unsigned j = 0; j < n_dim; j++)
8003  {
8004  outfile << node_coord[j+1] << " ";
8005  }
8006 
8007  // Output the boundary coordinate
8008  outfile << node_coord[0] << std::endl;
8009  }
8010 
8011  }
8012 
8013 #ifdef OOMPH_HAS_MPI
8014  //====================================================================
8015  // \short Creates the distributed domain representation. Joins the
8016  // original boundaires, shared boundaries and creates connections among
8017  // them to create the new polygons that represent the distributed
8018  // domain
8019  //====================================================================
8020  template<class ELEMENT>
8022  Vector<TriangleMeshPolygon *> &polygons_pt,
8023  Vector<TriangleMeshOpenCurve*> &open_curves_pt)
8024  {
8025  // Get the outer polygons, internal polygons, internal open curves
8026  // and join them with the shared polylines to create the distributed
8027  // domain representation (the new outer, internal polygons, and new
8028  // internal open curves)
8029 
8030  // Get the rank of the current processor
8031  const unsigned my_rank = this->communicator_pt()->my_rank();
8032 
8033  // *********************************************************************
8034  // Step (2) Get the outer, internal and shared boundaries to create the
8035  // new polygons
8036  // *********************************************************************
8037 
8038  // *********************************************************************
8039  // Step (2.1) Get the outer boundaries and check if it is necessary to use
8040  // a new representation (for example when the boundary was splitted in
8041  // the distribution process)
8042  // *********************************************************************
8043 
8044  // Storage for new created polylines, non sorted
8045  Vector<TriangleMeshPolyLine *> unsorted_outer_polyline_pt;
8046 
8047  // Storing for the polylines on the boundaries
8048  // The first index is for a set of connected polylines
8049  // The second index is for a polyline on a set of connected polylines
8050  Vector<Vector<TriangleMeshPolyLine *> > sorted_outer_curves_pt;
8051 
8052  // Copy the outer boundaries to the vector of polylines
8053  const unsigned nouter=this->Outer_boundary_pt.size();
8054  for (unsigned i = 0; i < nouter; i++)
8055  {
8056  const unsigned npolylines = this->Outer_boundary_pt[i]->npolyline();
8057  for (unsigned p = 0; p < npolylines; p++)
8058  {
8059  // Pointer to the current polyline
8060  TriangleMeshPolyLine *tmp_polyline_pt =
8061  this->Outer_boundary_pt[i]->polyline_pt(p);
8062  const unsigned nvertex = tmp_polyline_pt->nvertex();
8063  if (nvertex > 0)
8064  {
8065  // Get the boundary id of the polyline and check if that boundary
8066  // needs a new representation (for example when the boundary was
8067  // splitted in the distribution process)
8068  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8069  if (!boundary_was_splitted(bound_id))
8070  {
8071  unsorted_outer_polyline_pt.push_back(tmp_polyline_pt);
8072  } // if (!boundary_was_splitted(bound_id))
8073  else
8074  {
8075  // Get the polylines that will represent this boundary
8076  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8077  boundary_subpolylines(bound_id);
8078  const unsigned nsub_poly = tmp_vector_polylines.size();
8079 #ifdef PARANOID
8080  if (nsub_poly <= 1)
8081  {
8082  std::ostringstream error_message;
8083  error_message
8084  <<"The boundary ("<<bound_id<<") was marked to be splitted but\n"
8085  <<"there are only ("<<nsub_poly<<") polylines to represent it.\n";
8086  throw OomphLibError(error_message.str(),
8087  OOMPH_CURRENT_FUNCTION,
8088  OOMPH_EXCEPTION_LOCATION);
8089  }
8090 #endif
8091  // Add the new representation of the polylines (sub-polylines)
8092  // to represent this boundary
8093  for (unsigned isub = 0; isub < nsub_poly; isub++)
8094  {
8095  unsorted_outer_polyline_pt.push_back(tmp_vector_polylines[isub]);
8096 #ifdef PARANOID
8097  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8098  if (nsvertex == 0)
8099  {
8100  std::ostringstream error_message;
8101  error_message
8102  << "The current chunk ("<< isub <<") of the polyline with\n"
8103  << "boundary id (" << bound_id << ") has no vertices\n";
8104  throw OomphLibError(error_message.str(),
8105  OOMPH_CURRENT_FUNCTION,
8106  OOMPH_EXCEPTION_LOCATION);
8107  } // if (nsvertex == 0)
8108 #endif // #ifdef PARANOID
8109  } // for (isub < nsub_poly)
8110  } // else if (!boundary_was_splitted(bound_id))
8111  } // if (nvertex > 0)
8112  } // for (p < npolylines)
8113  } // for (i < nouter)
8114 
8115  // Get the number of unsorted polylines
8116  unsigned nunsorted_outer_polyline = unsorted_outer_polyline_pt.size();
8117  if (nunsorted_outer_polyline > 0)
8118  {
8119 
8120  // Now that we have all the new unsorted polylines it is time to sort them
8121  // so they be all contiguous
8122  sort_polylines_helper(unsorted_outer_polyline_pt, sorted_outer_curves_pt);
8123 
8124  } // if (nunsorted_outer_polyline > 0)
8125 
8126  // *********************************************************************
8127  // Step (2.2) Get the internal closed boundaries and check if it is
8128  // necessary to use a new representation (for example when the boundary
8129  // was splitted in the distribution process)
8130  // *********************************************************************
8131 
8132  // Storage for new created polylines, non sorted
8133  Vector<TriangleMeshPolyLine *> unsorted_internal_closed_polyline_pt;
8134 
8135  // Storing for the polylines on the boundaries
8136  // The first index is for a set of connected polylines
8137  // The second index is for a polyline on a set of connected polylines
8138  Vector<Vector<TriangleMeshPolyLine *> > sorted_internal_closed_curves_pt;
8139 
8140  // Copy the internal closed boundaries to the vector of polylines
8141  const unsigned ninternal_closed=this->Internal_polygon_pt.size();
8142  for (unsigned i = 0; i < ninternal_closed; i++)
8143  {
8144  const unsigned npolylines = this->Internal_polygon_pt[i]->npolyline();
8145  for (unsigned p = 0; p < npolylines; p++)
8146  {
8147  // Pointer to the current polyline
8148  TriangleMeshPolyLine *tmp_polyline_pt =
8149  this->Internal_polygon_pt[i]->polyline_pt(p);
8150  const unsigned nvertex = tmp_polyline_pt->nvertex();
8151  if (nvertex > 0)
8152  {
8153  // Get the boundary id of the polyline and check if that boundary
8154  // needs a new representation (for example when the boundary was
8155  // splitted in the distribution process)
8156  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8157  if (!boundary_was_splitted(bound_id))
8158  {
8159  unsorted_internal_closed_polyline_pt.push_back(tmp_polyline_pt);
8160  } // if (!boundary_was_splitted(bound_id))
8161  else
8162  {
8163  // Get the polylines that will represent this boundary
8164  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8165  boundary_subpolylines(bound_id);
8166  const unsigned nsub_poly = tmp_vector_polylines.size();
8167 #ifdef PARANOID
8168  if (nsub_poly <= 1)
8169  {
8170  std::ostringstream error_message;
8171  error_message
8172  <<"The boundary ("<<bound_id<<") was marked to be splitted but\n"
8173  <<"there are only ("<<nsub_poly<<") polylines to represent it.\n";
8174  throw OomphLibError(error_message.str(),
8175  OOMPH_CURRENT_FUNCTION,
8176  OOMPH_EXCEPTION_LOCATION);
8177  }
8178 #endif
8179  // Add the new representation of the polylines (sub-polylines)
8180  // to represent this boundary
8181  for (unsigned isub = 0; isub < nsub_poly; isub++)
8182  {
8183  unsorted_internal_closed_polyline_pt.push_back(tmp_vector_polylines[isub]);
8184 #ifdef PARANOID
8185  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8186  if (nsvertex == 0)
8187  {
8188  std::ostringstream error_message;
8189  error_message
8190  << "The current chunk ("<< isub <<") of the polyline with\n"
8191  << "boundary id (" << bound_id << ") has no vertices\n";
8192  throw OomphLibError(error_message.str(),
8193  OOMPH_CURRENT_FUNCTION,
8194  OOMPH_EXCEPTION_LOCATION);
8195  } // if (nsvertex == 0)
8196 #endif // #ifdef PARANOID
8197  } // for (isub < nsub_poly)
8198  } // else if (!boundary_was_splitted(bound_id))
8199  } // if (nvertex > 0)
8200  } // for (p < npolylines)
8201  } // for (i < ninternal_closed)
8202 
8203  const unsigned nunsorted_internal_closed_polyline =
8204  unsorted_internal_closed_polyline_pt.size();
8205 
8206  if (nunsorted_internal_closed_polyline > 0)
8207  {
8208  // Now that we have all the new unsorted polylines it is time to sort them
8209  // so they be all contiguous
8210  sort_polylines_helper(unsorted_internal_closed_polyline_pt,
8211  sorted_internal_closed_curves_pt);
8212  }
8213 
8214  // *********************************************************************
8215  // Step (2.3) Get the internal open boundaries and check if it is
8216  // necessary to use a new representation (for example when the boundary
8217  // was splitted in the distribution process)
8218  // *********************************************************************
8219 
8220  // Storage for new created polylines, non sorted
8221  Vector<TriangleMeshPolyLine *> unsorted_internal_open_polyline_pt;
8222 
8223  // Storing for the polylines on the boundaries
8224  // The first index is for a set of connected polylines
8225  // The second index is for a polyline on a set of connected polylines
8226  Vector<Vector<TriangleMeshPolyLine *> > sorted_internal_open_curves_pt;
8227 
8228  // Copy the internal open boundaries to the vector of polylines
8229  const unsigned ninternal_open = this->Internal_open_curve_pt.size();
8230  for (unsigned i = 0; i < ninternal_open; i++)
8231  {
8232  const unsigned ncurve_section =
8233  this->Internal_open_curve_pt[i]->ncurve_section();
8234  for (unsigned p = 0; p < ncurve_section; p++)
8235  {
8236  // Pointer to the current polyline
8237  TriangleMeshPolyLine *tmp_polyline_pt =
8238  this->Internal_open_curve_pt[i]->polyline_pt(p);
8239  const unsigned nvertex = tmp_polyline_pt->nvertex();
8240  if (nvertex > 0)
8241  {
8242  // Get the boundary id of the polyline and check if that boundary
8243  // needs a new representation (for example when the boundary was
8244  // splitted in the distribution process)
8245  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8246  if (!boundary_was_splitted(bound_id))
8247  {
8248  // Only include as internal boundaries those not marked as
8249  // shared boundaries
8250  if (!boundary_marked_as_shared_boundary(bound_id, 0))
8251  {
8252  unsorted_internal_open_polyline_pt.push_back(tmp_polyline_pt);
8253  }
8254  } // if (!boundary_was_splitted(bound_id))
8255  else
8256  {
8257  // Get the polylines that will represent this boundary
8258  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8259  boundary_subpolylines(bound_id);
8260  const unsigned nsub_poly = tmp_vector_polylines.size();
8261 #ifdef PARANOID
8262  if (nsub_poly <= 1)
8263  {
8264  std::ostringstream error_message;
8265  error_message
8266  <<"The boundary ("<<bound_id<<") was marked to be splitted but\n"
8267  <<"there are only ("<<nsub_poly<<") polylines to represent it.\n";
8268  throw OomphLibError(error_message.str(),
8269  OOMPH_CURRENT_FUNCTION,
8270  OOMPH_EXCEPTION_LOCATION);
8271  }
8272 #endif
8273  // Add the new representation of the polylines (sub-polylines)
8274  // to represent this boundary
8275  for (unsigned isub = 0; isub < nsub_poly; isub++)
8276  {
8277  // Only include as internal boundaries those not marked as
8278  // shared boundaries
8279  if (!boundary_marked_as_shared_boundary(bound_id, isub))
8280  {
8281  unsorted_internal_open_polyline_pt.push_back(tmp_vector_polylines[isub]);
8282  }
8283 #ifdef PARANOID
8284  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8285  if (nsvertex == 0)
8286  {
8287  std::ostringstream error_message;
8288  error_message
8289  << "The current chunk ("<< isub <<") of the polyline with\n"
8290  << "boundary id (" << bound_id << ") has no vertices\n";
8291  throw OomphLibError(error_message.str(),
8292  OOMPH_CURRENT_FUNCTION,
8293  OOMPH_EXCEPTION_LOCATION);
8294  } // if (nsvertex == 0)
8295 #endif // #ifdef PARANOID
8296  } // for (isub < nsub_poly)
8297  } // else if (!boundary_was_splitted(bound_id))
8298  } // if (nvertex > 0)
8299  } // for (p < npolylines)
8300  } // for (i < ninternal_open)
8301 
8302  const unsigned nunsorted_internal_open_polyline =
8303  unsorted_internal_open_polyline_pt.size();
8304 
8305  if (nunsorted_internal_open_polyline > 0)
8306  {
8307  // Now that we have all the new unsorted polylines it is time to sort them
8308  // so they be all contiguous
8309  sort_polylines_helper(unsorted_internal_open_polyline_pt,
8310  sorted_internal_open_curves_pt);
8311  }
8312 
8313  // ********************************************************************
8314  // Step (2.4) Sort the polylines on the shared boundaries
8315  // ********************************************************************
8316 
8317  // Storage for new created polylines, non sorted
8318  Vector<TriangleMeshPolyLine *> unsorted_shared_polyline_pt;
8319 
8320  // Special storage for the shared polylines that will be also used
8321  // to connect with the internal boundaries
8322  Vector<TriangleMeshPolyLine *> unsorted_shared_to_internal_polyline_pt;
8323 
8324  // Storing for the polylines on the shared boundaries
8325  // The first index is for a set of connected polylines
8326  // The second index is for a polyline on a set of connected polylines
8327  Vector<Vector<TriangleMeshPolyLine *> > sorted_shared_curves_pt;
8328 
8329  // Copy the shared boudaries to the vector of polylines
8330  const unsigned ncurves = nshared_boundary_curves(my_rank);
8331  for (unsigned i = 0; i < ncurves; i++)
8332  {
8333  const unsigned npolylines = nshared_boundary_polyline(my_rank, i);
8334  for (unsigned p = 0; p < npolylines; p++)
8335  {
8336  const unsigned nvertex =
8337  shared_boundary_polyline_pt(my_rank, i, p)->nvertex();
8338  if (nvertex > 0)
8339  {
8340  TriangleMeshPolyLine *tmp_shared_poly_pt =
8341  shared_boundary_polyline_pt(my_rank, i, p);
8342 
8343  // First check if there are shared boundaries overlapping
8344  // internal boundaries
8345  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
8346  {
8347  // Get the boundary id of the shared polyline
8348  const unsigned shd_bnd_id = tmp_shared_poly_pt->boundary_id();
8349  // If the shared polyline is marked as internal boundary
8350  // then include it in the special storage to look for
8351  // connection with internal boundaries
8352  if (this->shared_boundary_overlaps_internal_boundary(shd_bnd_id))
8353  {
8354  unsorted_shared_to_internal_polyline_pt.push_back(
8355  tmp_shared_poly_pt);
8356  }
8357  }
8358  unsorted_shared_polyline_pt.push_back(tmp_shared_poly_pt);
8359  }
8360  }
8361  }
8362 
8363  // Get the total number of shared polylines
8364  const unsigned nunsorted_shared_polyline =
8365  unsorted_shared_polyline_pt.size();
8366 
8367  if (nunsorted_shared_polyline > 0)
8368  {
8369  // Now that we have all the new unsorted polylines it is time to
8370  // sort them so they be all contiguous
8371  sort_polylines_helper(unsorted_shared_polyline_pt, sorted_shared_curves_pt);
8372  }
8373 
8374  // ********************************************************************
8375  // Step (3) Join the boundaries (shared, internal and outer to
8376  // create the new polygons)
8377  // ********************************************************************
8378 
8379  // Create the set of curves that will be used to create the new polygons
8380  // Get the total number of curves
8381  const unsigned nouter_curves = sorted_outer_curves_pt.size();
8382  const unsigned ninternal_closed_curves =
8383  sorted_internal_closed_curves_pt.size();
8384  const unsigned nshared_curves = sorted_shared_curves_pt.size();
8385  const unsigned ntotal_curves = nouter_curves +
8386  ninternal_closed_curves +
8387  nshared_curves;
8388 
8389  // Add all the polylines to a container
8390  unsigned counter = 0;
8391  Vector<Vector<TriangleMeshPolyLine *> > all_curves_pt(ntotal_curves);
8392 
8393  // Add the shared curves first, this ensure the generation of
8394  // internal polygons defined by the shared boundaries
8395  for (unsigned i = 0; i < nshared_curves; i++,counter++)
8396  {
8397  all_curves_pt[counter] = sorted_shared_curves_pt[i];
8398  }
8399 
8400  // Add the internal polygons (if any)
8401  for (unsigned i = 0; i < ninternal_closed_curves; i++,counter++)
8402  {
8403  all_curves_pt[counter] = sorted_internal_closed_curves_pt[i];
8404  }
8405 
8406  // Add the outer polygons
8407  for (unsigned i = 0; i < nouter_curves; i++,counter++)
8408  {
8409  all_curves_pt[counter] = sorted_outer_curves_pt[i];
8410  }
8411 
8412  // Create the temporary version of the domain by joining the new
8413  // polylines
8414  this->create_tmp_polygons_helper(all_curves_pt,polygons_pt);
8415  // Create the new open curves
8416  this->create_tmp_open_curves_helper(sorted_internal_open_curves_pt,
8417  unsorted_shared_to_internal_polyline_pt,
8418  open_curves_pt);
8419 
8420  // ********************************************************************
8421  // Step (4) Create connections among the outer boundaries
8422  // (intersections with themselves)
8423  // ********************************************************************
8424 
8425  // After creating the new boundaries representation (polylines)
8426  // establish the connections of the shared boundaries (with
8427  // themselves or with the original boundaries). This avoids the
8428  // multiple definition of vertices in the domain which cause
8429  // problems when calling Triangle
8430 
8431  this->create_shared_polylines_connections();
8432 
8433  // ------------------------------------------------------------------
8434  // Compute the new holes information. Those from the
8435  // extra_holes_coordinates container, and those from the original
8436  // closed boundaries. Add the holes created by the halo elements
8437  // adjacent to the shared boundaries
8438 
8439  // The storage for the new holes, get those from the
8440  // extra_holes_coordinates container and those from the internal
8441  // closed boundaries that are defined as holes
8442  Vector<Vector<double> > new_holes_coordinates;
8443 
8444  // Copy the holes (those defined by the original internal closed
8445  // boundaries and those in the extra holes container)
8446 
8447  // The holes defined by the original internal closed boundaries
8448  const unsigned n_holes = this->Internal_polygon_pt.size();
8449  for (unsigned h = 0; h < n_holes; h++)
8450  {
8451  Vector<double> hole_coordinates =
8452  this->Internal_polygon_pt[h]->internal_point();
8453  // If the closed boundary is a hole, then copy its hole
8454  if (!hole_coordinates.empty())
8455  {
8456  new_holes_coordinates.push_back(hole_coordinates);
8457  }
8458  } // for (h < n_holes)
8459 
8460  // Is this the first time we are going to copy the extra holes
8461  // coordinates
8462  if (First_time_compute_holes_left_by_halo_elements)
8463  {
8464  // The holes in the extra holes container
8465  const unsigned n_extra_holes = Extra_holes_coordinates.size();
8466  for (unsigned h = 0; h < n_extra_holes; h++)
8467  {
8468  Vector<double> hole_coordinates = Extra_holes_coordinates[h];
8469  new_holes_coordinates.push_back(hole_coordinates);
8470  } // for (h < n_extra_holes)
8471 
8472  // Copy the extra holes coordinates
8473  Original_extra_holes_coordinates = Extra_holes_coordinates;
8474 
8475  // Set the flag to false
8476  First_time_compute_holes_left_by_halo_elements = false;
8477 
8478  } // if (First_time_compute_holes_left_by_halo_elements)
8479  else
8480  {
8481  // Not the first time, then only copy the original extra holes
8482  // coordinates
8483  const unsigned n_original_extra_holes =
8484  Original_extra_holes_coordinates.size();
8485  for (unsigned h = 0; h < n_original_extra_holes; h++)
8486  {
8487  Vector<double> hole_coordinates = Original_extra_holes_coordinates[h];
8488  new_holes_coordinates.push_back(hole_coordinates);
8489  } // for (h < n_original_extra_holes)
8490  }
8491 
8492  // Add the holes created by the halo elements adjacent to the shared
8493  // boundaries
8494  compute_holes_left_by_halo_elements_helper(new_holes_coordinates);
8495 
8496  // Update the holes information, only use the coordinate inside the
8497  // poylgons that define the new domain
8498  update_holes_information_helper(polygons_pt, new_holes_coordinates);
8499 
8500  // tachidok Clear the storage by now
8501  //new_holes_coordinates.clear();
8502 
8503  // Now copy the info. in the extra holes coordinates container
8504  Extra_holes_coordinates = new_holes_coordinates;
8505 
8506  // Do not delete halo(ed) info., this will be "deleted"
8507  // automatically by not passing that information to the new adapted
8508  // mesh. Once the transfer of target areas is performed the halo(ed)
8509  // information is no longer required
8510 
8511  }
8512 
8513  //======================================================================
8514  // \short Take the polylines from the shared boundaries and the boundaries
8515  // to create polygons
8516  //======================================================================
8517  template<class ELEMENT>
8520  &polylines_pt,
8521  Vector<TriangleMeshPolygon *> &polygons_pt)
8522  {
8523  // Each vector of polylines (curve) is already sorted, it means that
8524  // all the polylines on the vector polylines_pt[i] point to the same
8525  // direction
8526 
8527  // --- Using this fact we should compare the first and last points from
8528  // these arrays of polylines (curves) and compare with the others
8529  // vectors of polylines (curves) end points
8530  // --- Once created a closed curve create a polygon
8531 
8532  // The number of curves
8533  const unsigned ncurves = polylines_pt.size();
8534 
8535  // The number of non sorted curves
8536  const unsigned nunsorted_curves = ncurves;
8537  // The number of sorted curves
8538  unsigned nsorted_curves = 0;
8539 
8540  // Vector to know which ncurve is already done
8541  std::vector<bool> done_curve(ncurves);
8542 
8543  do
8544  {
8545  // The list where to add the curves so that they be contiguous
8546  std::list<Vector<TriangleMeshPolyLine*> > list_building_polygon_pt;
8547 #ifdef PARANOID
8548  // Flag to indicate that a root curve was found
8549  bool root_curve_found = false;
8550 #endif
8551 
8552  // The index for the root_curve (we use it in further iterations as the
8553  // starting index so we dont need to search in already done curves)
8554  unsigned root_curve_idx = 0;
8555 
8556  // Get the root curve
8557  for (unsigned ic = 0; ic < ncurves; ic++)
8558  {
8559  if (!done_curve[ic])
8560  {
8561  root_curve_idx = ic;
8562  nsorted_curves++;
8563 #ifdef PARANOID
8564  root_curve_found = true;
8565 #endif
8566  done_curve[ic] = true;
8567  // ... break the loop
8568  break;
8569  }
8570  }
8571 
8572 #ifdef PARANOID
8573  if (!root_curve_found)
8574  {
8575  std::stringstream err;
8576  err <<"The root curve to create a polygon from the shared and "
8577  <<"original boundaries was not found!!!\n";
8578  throw OomphLibError(err.str(),
8579  "TriangleMesh::create_tmp_polygons_helper()",
8580  OOMPH_EXCEPTION_LOCATION);
8581  }
8582 #endif
8583 
8584  // Get the root curve
8585  Vector<TriangleMeshPolyLine*> root_curve_pt=polylines_pt[root_curve_idx];
8586 
8587  // Add the root curve to the list
8588  list_building_polygon_pt.push_back(root_curve_pt);
8589 
8590  // Get the initial and final vertices from the root curve
8591  Vector<double> root_curve_initial_vertex(2);
8592  Vector<double> root_curve_final_vertex(2);
8593 
8594  // We need to get the number of polylines that compose the root curve
8595  const unsigned nroot_curve_polyline = root_curve_pt.size();
8596  // ... and now get the initial and final vertex
8597  root_curve_pt[0]->initial_vertex_coordinate(root_curve_initial_vertex);
8598  root_curve_pt[nroot_curve_polyline-1]->
8599  final_vertex_coordinate(root_curve_final_vertex);
8600 
8601  // First check if it already create a polygon
8602  double diff =
8603  ((root_curve_initial_vertex[0] - root_curve_final_vertex[0])*
8604  (root_curve_initial_vertex[0] - root_curve_final_vertex[0]))
8605  +
8606  ((root_curve_initial_vertex[1] - root_curve_final_vertex[1])*
8607  (root_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8608  diff = sqrt(diff);
8610  {
8611  // The polyline already create a Polygon, then create it!!!
8612  // Create the curve section representation of the current root curve
8614  curve_section_pt(nroot_curve_polyline);
8615 
8616  // Copy the polylines into its curve section representation
8617  for (unsigned i = 0; i < nroot_curve_polyline; i++)
8618  {curve_section_pt[i] = root_curve_pt[i];}
8619 
8620  // ... and create the Polygon
8621  TriangleMeshPolygon *new_polygon_pt =
8622  new TriangleMeshPolygon(curve_section_pt);
8623 
8624  // Mark the polygon for deletion (in the destructor)
8625  this->Free_polygon_pt.insert(new_polygon_pt);
8626 
8627  // Add the polygon to the output polygons
8628  polygons_pt.push_back(new_polygon_pt);
8629  } // (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8630  // when the curve creates a Polygon by itself
8631  else
8632  {
8633  // Flag to continue iterating while curves be added to the left
8634  // or right of the list of curves
8635  bool added_curve = false;
8636 #ifdef PARANOID
8637  // Flag to know if the "loop" finish because a polygon was
8638  // created or because no more curves can be added to the left or
8639  // right
8640  bool polygon_created = false;
8641 #endif
8642  do
8643  {
8644  added_curve = false;
8645  // If the root curve does not create a closed polygon then add curves
8646  // to the left or right until the curves create a closed polygon
8647  for (unsigned ic = root_curve_idx+1; ic < ncurves; ic++)
8648  {
8649  if (!done_curve[ic])
8650  {
8651  // Get the current curve
8652  Vector<TriangleMeshPolyLine*> current_curve_pt =
8653  polylines_pt[ic];
8654 
8655  // We need to get the number of polylines that compose the
8656  // current curve
8657  const unsigned ncurrent_curve_polyline = current_curve_pt.size();
8658 
8659  // ... and get the initial and final coordinates for the current
8660  // curve
8661  Vector<double> current_curve_initial_vertex(2);
8662  Vector<double> current_curve_final_vertex(2);
8663 
8664  current_curve_pt[0]->
8665  initial_vertex_coordinate(current_curve_initial_vertex);
8666  current_curve_pt[ncurrent_curve_polyline-1]->
8667  final_vertex_coordinate(current_curve_final_vertex);
8668 
8669  // ---------------------------------------------------------------
8670  // Start adding curves to the left or right
8671  // ---------------------------------------------------------------
8672  diff =
8673  ((current_curve_final_vertex[0] - root_curve_initial_vertex[0])*
8674  (current_curve_final_vertex[0] - root_curve_initial_vertex[0]))
8675  +
8676  ((current_curve_final_vertex[1] - root_curve_initial_vertex[1])*
8677  (current_curve_final_vertex[1] - root_curve_initial_vertex[1]));
8678  diff = sqrt(diff);
8679  // CURRENT curve to the LEFT of the ROOT curve
8681  {
8682  // Add the current curve to the left
8683  list_building_polygon_pt.push_front(current_curve_pt);
8684  // Mark the curve as done
8685  done_curve[ic] = true;
8686  // Update the initial vertex values
8687  root_curve_initial_vertex[0] = current_curve_initial_vertex[0];
8688  root_curve_initial_vertex[1] = current_curve_initial_vertex[1];
8689  // Increase the number of sorted curves
8690  nsorted_curves++;
8691  // Set the flag to indicate that a curve was added to the list
8692  added_curve = true;
8693  break;
8694  }
8695 
8696  diff =
8697  ((current_curve_initial_vertex[0] - root_curve_initial_vertex[0])*
8698  (current_curve_initial_vertex[0] - root_curve_initial_vertex[0]))
8699  +
8700  ((current_curve_initial_vertex[1] - root_curve_initial_vertex[1])*
8701  (current_curve_initial_vertex[1] - root_curve_initial_vertex[1]));
8702  diff = sqrt(diff);
8703  // CURRENT curve to the LEFT of the ROOT curve but INVERTED
8705  {
8707  tmp_curve_pt(ncurrent_curve_polyline);
8708  // Reverse each polyline and back them up
8709  for (unsigned it = 0; it < ncurrent_curve_polyline; it++)
8710  {
8711  current_curve_pt[it]->reverse();
8712  tmp_curve_pt[it] = current_curve_pt[it];
8713  }
8714  // Now copy them back but in reverse order
8715  unsigned count = 0;
8716  for (int i = ncurrent_curve_polyline - 1; i >= 0; i--,count++)
8717  {current_curve_pt[count] = tmp_curve_pt[i];}
8718  // Add the current curve to the left
8719  list_building_polygon_pt.push_front(current_curve_pt);
8720  // Mark the curve as done
8721  done_curve[ic] = true;
8722  // Update the initial vertex values
8723  root_curve_initial_vertex[0] = current_curve_final_vertex[0];
8724  root_curve_initial_vertex[1] = current_curve_final_vertex[1];
8725  // Increase the number of sorted curves
8726  nsorted_curves++;
8727  // Set the flag to indicate that a curve was added to the list
8728  added_curve = true;
8729  break;
8730  }
8731 
8732  diff =
8733  ((current_curve_initial_vertex[0] - root_curve_final_vertex[0])*
8734  (current_curve_initial_vertex[0] - root_curve_final_vertex[0]))
8735  +
8736  ((current_curve_initial_vertex[1] - root_curve_final_vertex[1])*
8737  (current_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8738  diff = sqrt(diff);
8739  // CURRENT curve to the RIGHT of the ROOT curve
8741  {
8742  // Add the current curve to the right
8743  list_building_polygon_pt.push_back(current_curve_pt);
8744  // Mark the curve as done
8745  done_curve[ic] = true;
8746  // Update the initial vertex values
8747  root_curve_final_vertex[0] = current_curve_final_vertex[0];
8748  root_curve_final_vertex[1] = current_curve_final_vertex[1];
8749  // Increase the number of sorted curves
8750  nsorted_curves++;
8751  // Set the flag to indicate that a curve was added to the list
8752  added_curve = true;
8753  break;
8754  }
8755 
8756  diff =
8757  ((current_curve_final_vertex[0] - root_curve_final_vertex[0])*
8758  (current_curve_final_vertex[0] - root_curve_final_vertex[0]))
8759  +
8760  ((current_curve_final_vertex[1] - root_curve_final_vertex[1])*
8761  (current_curve_final_vertex[1] - root_curve_final_vertex[1]));
8762  diff = sqrt(diff);
8763  // CURRENT curve to the RIGHT of the ROOT curve but INVERTED
8765  {
8767  tmp_curve_pt(ncurrent_curve_polyline);
8768  // Reverse each polyline and back them up
8769  for (unsigned it = 0; it < ncurrent_curve_polyline; it++)
8770  {
8771  current_curve_pt[it]->reverse();
8772  tmp_curve_pt[it] = current_curve_pt[it];
8773  }
8774  // Now copy them back but in reverse order
8775  unsigned count = 0;
8776  for (int i = ncurrent_curve_polyline - 1; i >= 0; i--,count++)
8777  {current_curve_pt[count] = tmp_curve_pt[i];}
8778  // Add the current curve to the right
8779  list_building_polygon_pt.push_back(current_curve_pt);
8780  // Mark the curve as done
8781  done_curve[ic] = true;
8782  // Update the initial vertex values
8783  root_curve_final_vertex[0] = current_curve_initial_vertex[0];
8784  root_curve_final_vertex[1] = current_curve_initial_vertex[1];
8785  // Increase the number of sorted curves
8786  nsorted_curves++;
8787  // Set the flag to indicate that a curve was added to the list
8788  added_curve = true;
8789  break;
8790  }
8791 
8792  } // if (!done_curve[ic])
8793 
8794  } // for (ic < ncurves)
8795 
8796  // After adding a curve check if it is possible to create a polygon
8797  double diff =
8798  ((root_curve_initial_vertex[0] - root_curve_final_vertex[0])*
8799  (root_curve_initial_vertex[0] - root_curve_final_vertex[0]))
8800  +
8801  ((root_curve_initial_vertex[1] - root_curve_final_vertex[1])*
8802  (root_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8803  diff = sqrt(diff);
8805  {
8806  // If the curves already create a Polygon then go out of the
8807  // loop and create the Polygon
8808  added_curve = false;
8809 #ifdef PARANOID
8810  // Set the flag to indicate that a Polygon has been created
8811  polygon_created = true;
8812 #endif
8813  } // (diff <
8814  // ToleranceForVertexMismatchInPolygons::Tolerable_error)
8815  // when the curve creates a Polygon by itself
8816 
8817  }while(added_curve);
8818 
8819 #ifdef PARANOID
8820  if (!polygon_created)
8821  {
8822  std::stringstream error_message;
8823  error_message
8824  << "It was no possible to create a TriangleMeshPolygon with "
8825  << "the input set of curves\n"
8826  << "These are the initial and final vertices in the current "
8827  << "sorted list of\nTriangleMeshPolyLines\n\n";
8828  Vector<double> init_vertex(2);
8829  Vector<double> final_vertex(2);
8830  unsigned icurve = 0;
8831  for (std::list<Vector<TriangleMeshPolyLine*> >::iterator it
8832  = list_building_polygon_pt.begin();
8833  it != list_building_polygon_pt.end(); it++, icurve++)
8834  {
8835  const unsigned ncurrent_curve_polyline = (*it).size();
8836  error_message
8837  << "TriangleMeshCurve #" << icurve << "\n"
8838  << "-----------------------------------\n";
8839  for (unsigned ip = 0; ip < ncurrent_curve_polyline; ip++)
8840  {
8841  Vector<double> init_vertex(2);
8842  Vector<double> final_vertex(2);
8843  (*it)[ip]->initial_vertex_coordinate(init_vertex);
8844  (*it)[ip]->final_vertex_coordinate(final_vertex);
8845  error_message
8846  <<"TriangleMeshPolyLine #" << ip << "\n"
8847  <<"Initial vertex: ("<<init_vertex[0]<<","<<init_vertex[1]<<")\n"
8848  <<"Final vertex: ("<<final_vertex[0]<<","<<final_vertex[1]<<")\n";
8849  } // for (ip < ncurrent_curve_polyline)
8850  } // for (it != list_building_polygon_pt.end())
8851 
8852  throw OomphLibError(error_message.str(),
8853  "TriangleMesh::create_tmp_polygons_helper()",
8854  OOMPH_EXCEPTION_LOCATION);
8855 
8856  } // if (!polygon_created)
8857 #endif
8858 
8859  // Create the polygon after joining the curves
8860  unsigned ntotal_polylines = 0;
8861  // Get the total number of polylines
8862  for (std::list<Vector<TriangleMeshPolyLine*> >::iterator it
8863  = list_building_polygon_pt.begin();
8864  it != list_building_polygon_pt.end(); it++)
8865  {
8866  ntotal_polylines+=(*it).size();
8867  }
8868 
8869  // Create the curve section representation of the curves on the list
8870  Vector<TriangleMeshCurveSection*> curve_section_pt(ntotal_polylines);
8871 
8872  // Copy the polylines into its curve section representation
8873  unsigned counter = 0;
8874  for (std::list<Vector<TriangleMeshPolyLine*> >::iterator it
8875  = list_building_polygon_pt.begin();
8876  it != list_building_polygon_pt.end(); it++)
8877  {
8878  const unsigned ncurrent_curve_polyline = (*it).size();
8879  for (unsigned ip = 0; ip < ncurrent_curve_polyline; ip++,counter++)
8880  {
8881  curve_section_pt[counter] = (*it)[ip];
8882  } // for (ip < ncurrent_curve_polyline)
8883  } // Loop over the list of polylines
8884 
8885  // ... and create the Polygon
8886  TriangleMeshPolygon *new_polygon_pt =
8887  new TriangleMeshPolygon(curve_section_pt);
8888 
8889  // Mark the polygon for deletion (in the destructor)
8890  this->Free_polygon_pt.insert(new_polygon_pt);
8891 
8892  // Add the polygon to the output polygons
8893  polygons_pt.push_back(new_polygon_pt);
8894 
8895  } // else
8896  // (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8897 
8898  }while(nsorted_curves < nunsorted_curves);
8899 
8900  }
8901 
8902  //======================================================================
8903  //\short Take the polylines from the original open curves and created
8904  //new temporaly representations of open curves with the bits of
8905  //original curves not overlapped by shared boundaries
8906  //======================================================================
8907  template<class ELEMENT>
8909  Vector<Vector<TriangleMeshPolyLine *> > &sorted_open_curves_pt,
8910  Vector<TriangleMeshPolyLine*> &unsorted_shared_to_internal_poly_pt,
8911  Vector<TriangleMeshOpenCurve *> &open_curves_pt)
8912  {
8913  // Here search for the connections of the open curves remaining as
8914  // open curves with the shared boundaries markes as internal
8915  const unsigned ninternal_open_curves = sorted_open_curves_pt.size();
8916 
8917  // Once identified the connections created with the new internal
8918  // boundaries representations add them to the open curves container
8919  for (unsigned i = 0; i < ninternal_open_curves; i++)
8920  {
8921  // Create the curve section representation of the polylines
8922  const unsigned npoly = sorted_open_curves_pt[i].size();
8923  Vector<TriangleMeshCurveSection*> tmp_curve_section(npoly);
8924  for (unsigned j = 0; j < npoly; j++)
8925  {
8926  tmp_curve_section[j] = sorted_open_curves_pt[i][j];
8927  }
8928  // ... and create the Open Curve
8929  TriangleMeshOpenCurve *new_open_curve_pt =
8930  new TriangleMeshOpenCurve(tmp_curve_section);
8931 
8932  // Mark the open curve for deletion (in the destructor)
8933  this->Free_open_curve_pt.insert(new_open_curve_pt);
8934 
8935  // Add the open curve to the output open curves
8936  open_curves_pt.push_back(new_open_curve_pt);
8937 
8938  } // (i < ninternal_open_curves)
8939 
8940  }
8941 
8942  //======================================================================
8943  //\short Check for any possible connections that the array of sorted
8944  //nodes have with original boundary nodes, previous shared polyline
8945  //nodes or with itself polyline nodes. In case that there is a
8946  //connection, get the boundary id to which connects
8947  //======================================================================
8948  template<class ELEMENT>
8950  std::set<FiniteElement*> &element_in_processor_pt,
8951  const int &root_edge_bnd_id,
8952  std::map<std::pair<Node*,Node*>, bool> &overlapped_face,
8953  std::map<unsigned, std::map<Node*, bool> >
8954  &node_on_bnd_not_overlapped_by_shd_bnd,
8955  std::list<Node*> &current_polyline_nodes,
8956  std::map<unsigned, std::list<Node*> >
8957  &shared_bnd_id_to_sorted_list_node_pt,
8958  const unsigned &node_degree,
8959  Node* &new_node_pt,
8960  const bool called_from_load_balance)
8961  {
8962  // Initialize the flag to return
8963  int flag_to_return = -1;
8964 
8965  // --------------------------------------------------------------------
8966  // First try to find a connection with any original boundary (keep
8967  // in mind the case when internal boundaries may be overlapped by
8968  // shared boundaries)
8969  // --------------------------------------------------------------------
8970 
8971  // Check if the shared boundary is overlapping an internal boundary
8972  bool overlapping_internal_boundary = false;
8973  // The boundary id overlapped by the current shared boundary
8974  unsigned internal_overlaping_bnd_id = 0;
8975  if (root_edge_bnd_id != -1)
8976  {
8977  // Set the flat to true
8978  overlapping_internal_boundary = true;
8979  // Set the bnd id of the overlapped internal boundary
8980  internal_overlaping_bnd_id = static_cast<unsigned>(root_edge_bnd_id);
8981  } // if (root_edge_bnd_id != -1)
8982 
8983  // ---------------------------------------------------------------
8984  // Check if the connection is with an original boundary by checking
8985  // if the new node is a boundary node, and it lives in an element
8986  // that is part of the domain
8987  // ---------------------------------------------------------------
8988  if (new_node_pt->is_on_boundary())
8989  {
8990  // Flag to indicate if the node lives in a non overlapped boundary
8991  bool is_node_living_in_non_overlapped_boundary = false;
8992 
8993  // If the node is a boundary node then check in which boundary it
8994  // is
8995  const unsigned noriginal_bnd = this->initial_shared_boundary_id();
8996  for (unsigned bb=0;bb<noriginal_bnd;bb++)
8997  {
8998  // If the shared boundary overlaps an internal boundary it will
8999  // be indicated by (root_edge_bnd_id != -1), the original
9000  // internal boundary that overlaps is given by the
9001  // root_edge_bnd_id value. We skip that original internal
9002  // boundary because the new node will be obviously ON the
9003  // internal boundary
9004  if (overlapping_internal_boundary)
9005  {
9006  // Is the node on boundary bb?
9007  if (new_node_pt->is_on_boundary(bb))
9008  {
9009  // If overlaping then check that the boundary is different
9010  // from the one that is being overlapped, or if overlapped
9011  // then check that the node is on an edge on the bb
9012  // boundary not overlapped by a shared boundary
9013  const bool on_bnd_edge_not_overlapped_by_shd_bnd =
9014  node_on_bnd_not_overlapped_by_shd_bnd[bb][new_node_pt];
9015  if (bb != internal_overlaping_bnd_id ||
9016  ((bb == internal_overlaping_bnd_id) &&
9017  (on_bnd_edge_not_overlapped_by_shd_bnd)))
9018  {
9019  // Is the node living in a non overlapped boundary
9020  if (bb != internal_overlaping_bnd_id)
9021  {
9022  is_node_living_in_non_overlapped_boundary = true;
9023  }
9024 
9025  // Now we need to check that the node lies on a boundary
9026  // that still exist (the elements associated to the
9027  // boundary may have been removed at the mesh distribution
9028  // stage). The node may be still marked as a boundary node
9029  // but the boundary may not have elements associated.
9030 
9031  // Get the number of elements in the boundary
9032  const unsigned n_bound_ele = this->nboundary_element(bb);
9033  if (n_bound_ele > 0)
9034  {
9035  // Check that node lies on a nonhalo element, those are
9036  // the elements used to update the domain representation
9037  for (unsigned e = 0; e < n_bound_ele; e++)
9038  {
9039  // Get the boundary bulk element
9040  FiniteElement* bulk_ele_pt = this->boundary_element_pt(bb, e);
9041  // Check if the element will be retained, it means it
9042  // is a nonhalo element
9043  std::set<FiniteElement*>::iterator it =
9044  element_in_processor_pt.find(bulk_ele_pt);
9045  // If found then check if the node live in the element
9046  if (it!=element_in_processor_pt.end())
9047  {
9048  // Found the node in the nonhalo face element
9049  bool found_node = false;
9050  // Get the face index
9051  int face_index = this->face_index_at_boundary(bb, e);
9052  // Create the face element
9053  FiniteElement* face_ele_pt =
9054  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
9055  // Get the number of nodes in the face element
9056  const unsigned n_node_face = face_ele_pt->nnode();
9057  // Get the first and last node of the face element
9058  Node* first_node_pt = face_ele_pt->node_pt(0);
9059  Node* last_node_pt = face_ele_pt->node_pt(n_node_face-1);
9060  // Create the edge with the pair of nodes
9061  std::pair<Node*, Node*> tmp_edge =
9062  std::make_pair(first_node_pt, last_node_pt);
9063  // Check if the face element edge is overlapped by a
9064  // shared boundary
9065  // Is the face not overlapped?
9066  if (!overlapped_face[tmp_edge])
9067  {
9068  // Look for the node in the current face element
9069  for (unsigned n = 0; n < n_node_face; n++)
9070  {
9071  // Check for every individual node
9072  if (face_ele_pt->node_pt(n) == new_node_pt)
9073  {
9074  found_node = true;
9075  break;
9076  } // if (face_ele_pt->node_pt(n) == new_node_pt)
9077  } // for (n < n_node_face)
9078  } // if (!overlapped_face[tmp_edge])
9079  // Free the memory of the face element
9080  delete face_ele_pt;
9081  if (found_node)
9082  {
9083  // return the first original boundary id found,
9084  // does not matter if the node lies on more than
9085  // one original boundary (with boundary
9086  // elements). This is the original boundary id
9087  // that will be used to create the connection
9088  flag_to_return = bb;
9089  return flag_to_return;
9090  } // if (found_node)
9091 
9092  } // if (it!=element_in_processor_pt.end())
9093 
9094  } // for (e < n_bound_ele)
9095 
9096  } // if (n_bound_ele > 0)
9097 
9098  } // if (bb != internal_overlaping_bnd_id ||
9099  // ((bb == internal_overlaping_bnd_id) &&
9100  // (on_bnd_edge_not_overlapped_by_shd_bnd)))
9101 
9102  } // if (nod_pt->is_on_boundary(bb))
9103 
9104  } // if (overlapping_internal_boundary)
9105  else
9106  {
9107  // Is the node on boundary bb?
9108  if (new_node_pt->is_on_boundary(bb))
9109  {
9110  // Now we need to check that the node lies on a boundary
9111  // that still exist (the elements associated to the boundary
9112  // may have been removed at the mesh distribution
9113  // stage). The node may be still marked as a boundary node
9114  // but the boundary may not have elements associated.
9115 
9116  // Get the number of elements in the boundary
9117  const unsigned n_bound_ele = this->nboundary_element(bb);
9118  if (n_bound_ele > 0)
9119  {
9120  // Check that node lies on a nonhalo element, those are
9121  // the elements used to update the domain representation
9122  for (unsigned e = 0; e < n_bound_ele; e++)
9123  {
9124  // Get the boundary bulk element
9125  FiniteElement* bulk_ele_pt = this->boundary_element_pt(bb, e);
9126  // Check if the element will be retained, it means it is
9127  // a nonhalo element
9128  std::set<FiniteElement*>::iterator it =
9129  element_in_processor_pt.find(bulk_ele_pt);
9130  // If found then check if the node live in the element
9131  if (it!=element_in_processor_pt.end())
9132  {
9133  // Found the node in the nonhalo face element
9134  bool found_node = false;
9135  // Get the face index
9136  int face_index = this->face_index_at_boundary(bb, e);
9137  // Create the face element
9138  FiniteElement* face_ele_pt =
9139  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
9140  // Get the number of nodes in the face element
9141  const unsigned n_node_face = face_ele_pt->nnode();
9142  // Get the first and last node of the face element
9143  Node* first_node_pt = face_ele_pt->node_pt(0);
9144  Node* last_node_pt = face_ele_pt->node_pt(n_node_face-1);
9145  // Create the edge with the pair of nodes
9146  std::pair<Node*, Node*> tmp_edge =
9147  std::make_pair(first_node_pt, last_node_pt);
9148  // Check if the face element edge is overlapped by a
9149  // shared boundary
9150  // Is the face not overlapped?
9151  if (!overlapped_face[tmp_edge])
9152  {
9153  // Look for the node in the current face element
9154  for (unsigned n = 0; n < n_node_face; n++)
9155  {
9156  // Check for every individual node
9157  if (face_ele_pt->node_pt(n) == new_node_pt)
9158  {
9159  found_node = true;
9160  break;
9161  } // if (face_ele_pt->node_pt(n) == new_node_pt)
9162  } // for (n < n_node_face)
9163  } // if (!overlapped_face[tmp_edge])
9164  // Free the memory of the face element
9165  delete face_ele_pt;
9166  if (found_node)
9167  {
9168  // return the first original boundary id found, does
9169  // not matter if the node lies on more than one
9170  // original boundary (with boundary elements). This
9171  // is the original boundary id that will be used to
9172  // create the connection
9173  flag_to_return = bb;
9174  return flag_to_return;
9175  } // if (found_node)
9176 
9177  } // if (it!=element_in_processor_pt.end())
9178 
9179  } // for (e < n_bound_ele)
9180 
9181  } // if (n_bound_ele > 0)
9182 
9183  } // if (nod_pt->is_on_boundary(bb))
9184  } // else if (overlapping_internal_boundary)
9185  } // for (bb < noriginal_bnd)
9186 
9187  // We will only reach this stage when the node was found to be
9188  // connected to an original boundary but the element(s) on that
9189  // boundary where the node should live are not part of the domain.
9190  // Think in a corner of a triangle which touches the boundary
9191  // which elements will not be part of the domain
9192 
9193  // We need to break the currently forming polyline
9194  //flag_to_return = -3;
9195 
9196  // We need to break the currently forming polyline if and only if
9197  // the boundary(ies) in which the node is living is(are) not an
9198  // overlapped boundary
9199  if (!overlapping_internal_boundary)
9200  {
9201  // If the boundary(ies) in which the node is living is(are) an
9202  // overlapped boundary then break the break the formation of the
9203  // polyline
9204  flag_to_return = -3;
9205  }
9206  else
9207  {
9208  // The boundary is overlapped, if the node lives in a non
9209  // overlapped boundary then we can break the formation of the
9210  // polyline
9211  if (is_node_living_in_non_overlapped_boundary)
9212  {
9213  flag_to_return = -3;
9214  } // if (is_node_living_in_non_overlapped_boundar)y
9215 
9216  } // if (!overlapping_internal_boundary)
9217 
9218  } // if (new_node_pt->is_on_boundary())
9219 
9220  // Return inmediately if the connection is with an original boundary
9221  // whose elements are still part of the domain
9222  if (flag_to_return >= 0)
9223  {
9224  return flag_to_return;
9225  }
9226 
9227  // ----------------------------------------------------------------------
9228  // Secondly, if there is not a connection with any original
9229  // boundary, or if there is connection but with an original boundary
9230  // whose elements are not part of the domain, then check for
9231  // connections with previously created shared polylines
9232  // ----------------------------------------------------------------------
9233  // Store all the previous shared polylines to which the current
9234  // found is found to be connected
9235  Vector<unsigned> candidate_shared_bnd_to_connect;
9236  // Check for all the previous polylines except the current one
9237  for (std::map<unsigned, std::list<Node*> >::iterator it =
9238  shared_bnd_id_to_sorted_list_node_pt.begin();
9239  it != shared_bnd_id_to_sorted_list_node_pt.end();
9240  it++)
9241  {
9242  // Get the boundary id of the list of nodes that created the
9243  // polyline (the shared boundary id associated with the list of
9244  // nodes)
9245  const unsigned i_bnd_id = (*it).first;
9246  // Get an iterator pointer to the list of nodes of the shared
9247  // polyline
9248  std::list<Node*>::iterator it_list = (*it).second.begin();
9249  // Get the total number of nodes associated to the boundary
9250  const unsigned n_nodes = (*it).second.size();
9251  // Search for connections in the list of nodes
9252  for (unsigned i = 0; i < n_nodes; i++, it_list++)
9253  {
9254  // Is the node already part of any other shared boundary
9255  if ((*it_list) == new_node_pt)
9256  {
9257  // Include the i-th boundary id in the list of candidate
9258  // shared boundaries to connect
9259  candidate_shared_bnd_to_connect.push_back(i_bnd_id);
9260  // Break the look with the i-th shared boundary, check with
9261  // the others shared boundaries
9262  break;
9263  } // if ((*it_list) == new_node_pt)
9264 
9265  } // for (i < nnodes)
9266 
9267  } // Loop over the shared boundaries and associated nodes
9268 
9269  // Get the number of candidate shared boundaries to connect
9270  const unsigned n_candidate_shared_bnd_to_connect =
9271  candidate_shared_bnd_to_connect.size();
9272 
9273  // Is there a connection with any previous shared polyline
9274  if (n_candidate_shared_bnd_to_connect > 0)
9275  {
9276  // If called from load balance we do not need to check if the
9277  // shared boundary is part of the processor since it certanily is,
9278  // only the shared boundaries that are pare of the processor are
9279  // used to created connection when creating the new shared
9280  // boundaries in the load balance rutine
9281  if (called_from_load_balance)
9282  {
9283  return candidate_shared_bnd_to_connect[0];
9284  }
9285 
9286  // We need to ensure that the shared boundary to which we are
9287  // connecting is part of the current processor, if none of the
9288  // found shared bundaries is in the current processor then return
9289  // the flag for "connection with boundary not in the current
9290  // processor"
9291 
9292  // Store the shared boundaries associated with the current processor
9293  Vector<unsigned> shared_bound_in_this_proc;
9294 
9295  // Get the shared boundaries associated with the current processor
9296  shared_boundaries_in_this_processor(shared_bound_in_this_proc);
9297 
9298  // If any of the candidate shared boundaries to connect is in the
9299  // current processor then return that shared boundary id
9300 
9301  // The number of shared boundaries in the current processor
9302  const unsigned n_shared_bound_in_this_proc =
9303  shared_bound_in_this_proc.size();
9304 
9305  // Loop over the candidate shared boundaries to connect
9306  for (unsigned i = 0; i < n_candidate_shared_bnd_to_connect; i++)
9307  {
9308  // Get the i-th candidate shared boundary to connect
9309  const unsigned i_candidate_shared_bnd =
9310  candidate_shared_bnd_to_connect[i];
9311 
9312  // Loop over the shared boundaries in the current processor
9313  for (unsigned j = 0; j < n_shared_bound_in_this_proc; j++)
9314  {
9315  // Is the candidate boundary a shared boundary in this processor?
9316  if (i_candidate_shared_bnd == shared_bound_in_this_proc[j])
9317  {
9318  // Return the candidate shared boundary
9319  flag_to_return = i_candidate_shared_bnd;
9320  return flag_to_return;
9321  } // The candidate shared boundary is a boundary in the
9322  // current processor
9323 
9324  } // for (j < n_shared_bound_in_this_proc)
9325 
9326  } // for (i < n_candidate_shared_bnd_to_connect)
9327 
9328  // If non of the candidate shared boundaries to connect is in the
9329  // current processor the mark that we need to stop the addition of
9330  // vertices at this side of the polyline
9331  flag_to_return = -3;
9332 
9333  } // if (n_candidate_shared_bnd_to_connect > 0)
9334 
9335  // Return inmediately if the connection is with a previuos shared
9336  // boundary
9337  if (flag_to_return >= 0)
9338  {
9339  return flag_to_return;
9340  }
9341 
9342  // ------------------------------------------------------------------
9343  // Finally,check for connections with the same polyline (the shared
9344  // boundary that is being constructed). We are trying to avoid loops
9345  // or connections with the same shared boundary that is why this is
9346  // checked at the end
9347  // ------------------------------------------------------------------
9348  unsigned nrepeated = 0;
9349  for (std::list<Node*>::iterator it_list = current_polyline_nodes.begin();
9350  it_list != current_polyline_nodes.end();
9351  it_list++)
9352  {
9353  // There must be at least one repeated node (the one that we have
9354  // just added, and it should be the first or last node)
9355  if ((*it_list) == new_node_pt) {nrepeated++;}
9356  }
9357  // If the number of repeated nodes is greater than one then the
9358  // polyline has a connection with itself
9359  if (nrepeated > 1)
9360  {
9361  // Return the flag value to indicate connection with itself, we
9362  // can not return the boundary id of the current polyline since it
9363  // has not been already assigned
9364  flag_to_return = -2;
9365  }
9366 
9367  // If there is no connection at all check the degree of the node, if
9368  // it is greater than 2 then return the flag to stop adding nodes
9369  // after this one
9370  if (node_degree > 2)
9371  {
9372  flag_to_return = -3;
9373  }
9374 
9375  // Return the flag
9376  return flag_to_return;
9377 
9378  }
9379 
9380  //======================================================================
9381  // \short Establish the connections of the polylines previously
9382  // marked as having connections. This connections were created in the
9383  // function TriangleMesh::create_polylines_from_halo_elements_helper().
9384  // In case of doing load balancing the connections were created by the
9385  // function RefineableTriangleMesh::create_new_shared_boundaries()
9386  // ======================================================================
9387  template<class ELEMENT>
9389  {
9390  // Get the rank of the current processor
9391  const unsigned my_rank = this->communicator_pt()->my_rank();
9392 
9393  // Get the shared curves associated with this processor
9394  Vector<Vector<TriangleMeshPolyLine*> > shared_curves_pt =
9395  this->Shared_boundary_polyline_pt[my_rank];
9396 
9397  // Loop through the shared boundaries on the current processor and
9398  // check if they are marked to create a connection
9399  const unsigned ncurves = shared_curves_pt.size();
9400  for (unsigned icurve = 0; icurve < ncurves; icurve++)
9401  {
9402  // Get the number of polylines in the current shared curve
9403  const unsigned npoly = shared_curves_pt[icurve].size();
9404  for (unsigned ipoly = 0; ipoly < npoly; ipoly++)
9405  {
9406  // Get the polyline representation of the shared boundary
9407  TriangleMeshPolyLine *shd_poly_pt = shared_curves_pt[icurve][ipoly];
9408 
9409  // Get the boundary id of the current polyline
9410  const unsigned bound_id = shd_poly_pt->boundary_id();
9411 
9412  // Is the left vertex connected
9413  const bool is_connected_to_the_left =
9414  shd_poly_pt->is_initial_vertex_connected();
9415 
9416  // Is the right vertex connected
9417  const bool is_connected_to_the_right =
9418  shd_poly_pt->is_final_vertex_connected();
9419 
9420  // -----------------------------------------------------------------
9421  // If there is a connection at one of the ends we need to
9422  // establish that connection
9423  if (is_connected_to_the_left || is_connected_to_the_right)
9424  {
9425  // Now get the new left and right vertices of the shared
9426  // polyline
9427  const unsigned n_vertex = shd_poly_pt->nvertex();
9428 
9429  // Now get the polylines to where the current shared boundary is
9430  // connected and create the connections
9431 
9432  // --------------------------------------------------------------
9433  // Connection to the left
9434  if (is_connected_to_the_left)
9435  {
9436  // Get the unsigned version of the bound id to connect to
9437  // the left
9438  const unsigned uconnection_to_the_left =
9439  shd_poly_pt->initial_vertex_connected_bnd_id();
9440 
9441  // The pointer to the boundary to connect
9442  TriangleMeshPolyLine *poly_to_connect_pt = 0;
9443 
9444  // Flag to indicate we are trying to connect to an split
9445  // boundary
9446  bool connecting_to_an_split_boundary = false;
9447 
9448  // Flag to indicate we are trying to connecto to an internal
9449  // boundary that is overlaped by a shared boundary
9450  bool connecting_to_an_overlaped_boundary = false;
9451 
9452  // Check if the connection is with itself
9453  if (uconnection_to_the_left == bound_id)
9454  {
9455  // Set the pointer to the polyline to connect
9456  poly_to_connect_pt = shd_poly_pt;
9457  }
9458  else
9459  {
9460  // Get the initial shared boundary ids
9461  const unsigned initial_shd_bnd_id = initial_shared_boundary_id();
9462  // Check if the boundary to connect is a shared polyline
9463  if (uconnection_to_the_left >= initial_shd_bnd_id)
9464  {
9465  // Get the polyline pointer representing the destination
9466  // boundary
9467  poly_to_connect_pt =
9468  boundary_polyline_pt(uconnection_to_the_left);
9469  } // if (uconnection_to_the_left >= initial_shd_bnd_id)
9470  else
9471  {
9472  // If we are going to connect to an original boundary
9473  // verify if the boundary was splitted during the
9474  // distribution process to consider all the chunks
9475  // (sub-polylines) of the boundary
9476  if (boundary_was_splitted(uconnection_to_the_left))
9477  {
9478  connecting_to_an_split_boundary = true;
9479  } // if (boundary_was_splitted(uconnection_to_the_left))
9480 
9481  // If we are going to connect to an original boundary
9482  // verify if the boundary, or any of its chunks is
9483  // marked to be overlapped by a shared boundary, if that
9484  // is the case we first check for connections in the
9485  // shared boundary that overlaps the internal boundary,
9486  // or the chunks, and then check for connections in the
9487  // original boundary
9488  if (connecting_to_an_split_boundary)
9489  {
9490  // Get the number of chucks that represent the
9491  // destination boundary
9492  const unsigned n_sub_poly =
9493  nboundary_subpolylines(uconnection_to_the_left);
9494  // Now loop over the chunks of the destination
9495  // boundary and if any of them is marked to be
9496  // overlaped by a shared boundary then set the flag
9497  // and break the loop
9498  for (unsigned ii =0; ii < n_sub_poly; ii++)
9499  {
9500  if (boundary_marked_as_shared_boundary(
9501  uconnection_to_the_left, ii))
9502  {
9503  // Mark the boundary as being overlaped by a
9504  // shared boundary
9505  connecting_to_an_overlaped_boundary = true;
9506  // Break, no need to look for more overlapings
9507  break;
9508  } // if (boundary_marked_as_shared_boundary(...))
9509  } // for (ii < n_sub_poly)
9510  } // if (connecting_to_an_split_boundary)
9511  else
9512  {
9513  // If not connecting to an split boundary then check
9514  // if the whole destination boundary is overlaped by
9515  // an internal boundary
9516  if (boundary_marked_as_shared_boundary(
9517  uconnection_to_the_left, 0))
9518  {
9519  // Mark the boundary as being overlaped by a shared
9520  // boundary
9521  connecting_to_an_overlaped_boundary = true;
9522  } // if (boundary_marked_as_shared_boundary(...))
9523  } // else if (connecting_to_an_split_boundary)
9524 
9525  // If we are connecting neither to an split boundary nor
9526  // an overlaped boundary then get the pointer to the
9527  // original boundary
9528  if (!(connecting_to_an_split_boundary ||
9529  connecting_to_an_overlaped_boundary))
9530  {
9531  // Get the polyline pointer representing the
9532  // destination boundary
9533  poly_to_connect_pt =
9534  boundary_polyline_pt(uconnection_to_the_left);
9535  } // else if (NOT split, NOT overlaped)
9536  } // else if (uconnection_to_the_left >= initial_shd_bnd_id)
9537 
9538  } // else if (uconnection_to_the_left == bound_id)
9539 
9540 #ifdef PARANOID
9541  // If we are not connecting to an original boundary
9542  // (connecting to the same shared boundary or to another
9543  // shared boundary) then the boundary should not be marked
9544  // as split
9545  if (!connecting_to_an_split_boundary)
9546  {
9547  if (boundary_was_splitted(uconnection_to_the_left))
9548  {
9549  std::stringstream error;
9550  error
9551  << "The current shared boundary (" << bound_id << ") was "
9552  << "marked to have a connection\nto the left with the "
9553  << "boundary (" << uconnection_to_the_left << ").\n"
9554  << "The problem is that the destination boundary (possibly\n"
9555  << "another shared boundary) is marked to be split\n"
9556  << "There should not be split shared boundaries\n\n";
9557  throw OomphLibError(
9558  error.str(),
9559  "TriangleMesh::create_shared_polylines_connections()",
9560  OOMPH_EXCEPTION_LOCATION);
9561  }
9562  } // if (!connecting_to_an_split_boundary)
9563 #endif
9564 
9565  // Now look for the vertex number on the destination
9566  // boundary(ies) -- in case that the boundary was split ---
9567 
9568  // Do not check for same orientation, that was previously
9569  // worked by interchanging the connections boundaries (if
9570  // necessary)
9571 
9572  // Get the left vertex in the shared boundary
9573  Vector<double> shd_bnd_left_vertex =
9574  shd_poly_pt->vertex_coordinate(0);
9575 
9576  // If the boundary was not split then ...
9577  if (!connecting_to_an_split_boundary)
9578  {
9579  // ... check if the boundary is marked to be overlaped by
9580  // a shared boundary
9581  if (!connecting_to_an_overlaped_boundary)
9582  {
9583  // If that is not the case then we can safely look for
9584  // the vertex number on the destination boundar
9585  unsigned vertex_index = 0;
9586 
9587  const bool found_vertex_index =
9588  get_connected_vertex_number_on_destination_polyline(
9589  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9590 
9591  // If we could not find the vertex index to connect then
9592  // we are in trouble
9593  if (!found_vertex_index)
9594  {
9595  std::stringstream error;
9596  error
9597  << "The current shared boundary (" << bound_id << ") was "
9598  << "marked to have a connection\nto the left with the "
9599  << "boundary (" << uconnection_to_the_left << ").\n"
9600  << "The problem is that the left vertex of the current\n"
9601  << "shared boundary is not in the list of vertices of the\n"
9602  << "boundary to connect.\n\n"
9603  << "This is the left vertex of the current shared boundary\n"
9604  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9605  << shd_bnd_left_vertex[1] << ")\n\n"
9606  << "This is the list of vertices on the destination "
9607  << "boundary\n";
9608  const unsigned n_v = poly_to_connect_pt->nvertex();
9609  for (unsigned i = 0; i < n_v; i++)
9610  {
9611  Vector<double> cvertex =
9612  poly_to_connect_pt->vertex_coordinate(i);
9613  error
9614  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "<<cvertex[1]<<")\n";
9615  }
9616  throw OomphLibError(
9617  error.str(),
9618  "TriangleMesh::create_shared_polylines_connections()",
9619  OOMPH_EXCEPTION_LOCATION);
9620  } // if (!found_vertex_index)
9621 
9622  // Create the connection, the left vertex of the current
9623  // shared boundary is connected with the vertex_index-th
9624  // vertex on the destination boundary
9626  poly_to_connect_pt, vertex_index);
9627 
9628  } // if (!connecting_to_an_overlaped_boundary)
9629  else
9630  {
9631  // If the boundary is marked to be overlaped by a shared
9632  // boundary then get that shared boundary and look for
9633  // the connection in that boundary
9634 
9635  // The vertex where to store the index to connect
9636  unsigned vertex_index = 0;
9637  // A flag to indicate if the connection was found
9638  bool found_vertex_index = false;
9639 
9640  // Get the shared boundary id that is overlaping the
9641  // internal boundary
9642  Vector<unsigned> dst_shd_bnd_ids;
9643  get_shared_boundaries_overlapping_internal_boundary(
9644  uconnection_to_the_left, dst_shd_bnd_ids);
9645 
9646  // Get the number of shared polylines that were found to
9647  // overlap the internal boundary
9648  const unsigned n_shd_bnd_overlap_int_bnd =
9649  dst_shd_bnd_ids.size();
9650 
9651  // Loop over the shared boundaries that overlap the
9652  // internal boundary and look for the vertex to connect
9653  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9654  {
9655  // Get the shared polyline
9656  const unsigned new_connection_to_the_left =
9657  dst_shd_bnd_ids[ss];
9658 
9659  // Get the shared polyline that is overlaping the
9660  // internal boundary
9661  poly_to_connect_pt =
9662  boundary_polyline_pt(new_connection_to_the_left);
9663 
9664  if (poly_to_connect_pt!=0)
9665  {
9666  // Look for the vertex number in the destination
9667  // shared polyline
9668  found_vertex_index =
9669  get_connected_vertex_number_on_destination_polyline(
9670  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9671  } // if (poly_to_connect_pt!=0)
9672 
9673  // If we have found the vertex to connect then
9674  // break the loop
9675  if (found_vertex_index)
9676  {
9677  break;
9678  } // if (found_vertex_index)
9679 
9680  } // for (ss < n_shd_bnd_overlaping_int_bnd)
9681 
9682 #ifdef PARANOID
9683  // If we could not find the vertex index to connect then
9684  // we are in trouble
9685  if (!found_vertex_index)
9686  {
9687  std::stringstream error;
9688  error
9689  << "The current shared boundary (" << bound_id << ") was "
9690  << "marked to have a connection\nto the left with the "
9691  << "boundary (" << uconnection_to_the_left << ").\n"
9692  << "This last boundary is marked to be overlaped by "
9693  << "shared boundaries\n"
9694  << "The problem is that the left vertex of the current\n"
9695  << "shared boundary is not in the list of vertices of the\n"
9696  << "boundary to connect.\n\n"
9697  << "This is the left vertex of the current shared boundary\n"
9698  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9699  << shd_bnd_left_vertex[1] << ")\n\n"
9700  << "This is the list of vertices on the destination "
9701  << "boundary\n";
9702  Vector<unsigned> dst_shd_bnd_ids;
9703  get_shared_boundaries_overlapping_internal_boundary(
9704  uconnection_to_the_left, dst_shd_bnd_ids);
9705  const unsigned n_shd_bnd_overlap_int_bnd =
9706  dst_shd_bnd_ids.size();
9707  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9708  {
9709  const unsigned new_connection_to_the_left =
9710  dst_shd_bnd_ids[ss];
9711  poly_to_connect_pt =
9712  boundary_polyline_pt(new_connection_to_the_left);
9713  if (poly_to_connect_pt != 0)
9714  {
9715  const unsigned shd_bnd_id_overlap =
9716  poly_to_connect_pt->boundary_id();
9717  error << "Shared boundary id("
9718  << shd_bnd_id_overlap << ")\n";
9719  const unsigned n_v = poly_to_connect_pt->nvertex();
9720  for (unsigned i = 0; i < n_v; i++)
9721  {
9722  Vector<double> cvertex =
9723  poly_to_connect_pt->vertex_coordinate(i);
9724  error
9725  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
9726  <<cvertex[1]<<")\n";
9727  }
9728  } // if (poly_to_connect_pt != 0)
9729  } // for (ss < n_shd_bnd_overlap_int_bnd)
9730 
9731  throw OomphLibError(
9732  error.str(),
9733  "TriangleMesh::create_shared_polylines_connections()",
9734  OOMPH_EXCEPTION_LOCATION);
9735 
9736  } // if (!found_vertex_index)
9737 #endif
9738 
9739  // Create the connection, the left vertex of the current
9740  // shared boundary is connected with the vertex_index-th
9741  // vertex on the destination boundary
9743  poly_to_connect_pt, vertex_index);
9744 
9745  } // else if (!connecting_to_an_overlaped_boundary)
9746 
9747  } // if (!connecting_to_an_split_boundary)
9748  else
9749  {
9750  // If the boundary was split then we need to look for the
9751  // vertex in the sub-polylines
9752 
9753  // Get the sub-polylines vector
9754  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
9755  boundary_subpolylines(uconnection_to_the_left);
9756 
9757  // Get the number of sub-polylines
9758  const unsigned nsub_poly = tmp_vector_subpolylines.size();
9759 #ifdef PARANOID
9760  if (nsub_poly <= 1)
9761  {
9762  std::ostringstream error_message;
9763  error_message
9764  <<"The boundary (" << uconnection_to_the_left << ") was "
9765  << "marked to be splitted but\n"
9766  << "there are only ("<<nsub_poly<<") polylines to "
9767  << "represent it.\n";
9768  throw OomphLibError(
9769  error_message.str(),
9770  "TriangleMesh::create_shared_polylines_connections()",
9771  OOMPH_EXCEPTION_LOCATION);
9772  } // if (nsub_poly <= 1)
9773 #endif
9774  // We need to check if the boundary is marked to be
9775  // overlaped by an internal boundary, if that is the case
9776  // we need to check for each indivual subpolyline, and for
9777  // those overlaped by a shared polyline look for the
9778  // vertex in the shared polyline representation instead of
9779  // the original subpolyline
9780 
9781  // ... check if the boundary is marked to be overlaped by
9782  // a shared boundary
9783  if (!connecting_to_an_overlaped_boundary)
9784  {
9785  // We can work without checking the subpolylines
9786  // individually
9787 
9788  // The vertex where to store the index to connect
9789  unsigned vertex_index = 0;
9790  // The subpoly number to connect
9791  unsigned sub_poly_to_connect = 0;
9792  // A flag to indicate if the connection was found
9793  bool found_vertex_index = false;
9794 
9795  // Look for the vertex number to connect on each of the
9796  // subpolyines
9797  for (unsigned isub = 0; isub < nsub_poly; isub++)
9798  {
9799  // Assign the pointer to the sub-polyline
9800  poly_to_connect_pt = tmp_vector_subpolylines[isub];
9801  // Search for the vertex in the current sub-polyline
9802  found_vertex_index =
9803  get_connected_vertex_number_on_destination_polyline(
9804  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9805  // If we have found the vertex to connect then break the
9806  // loop
9807  if (found_vertex_index)
9808  {
9809  // But first save the subpoly number (chunk), that
9810  // will be used to perform the connection
9811  sub_poly_to_connect = isub;
9812  break;
9813  } // if (found_vertex_index)
9814  } // for (isub < nsub_poly)
9815 
9816 #ifdef PARANOID
9817  // If we could not find the vertex index to connect then
9818  // we are in trouble
9819  if (!found_vertex_index)
9820  {
9821  std::stringstream error;
9822  error
9823  << "The current shared boundary (" << bound_id << ") was "
9824  << "marked to have a connection\nto the left with the "
9825  << "boundary (" << uconnection_to_the_left << ").\n"
9826  << "The problem is that the left vertex of the current\n"
9827  << "shared boundary is not in the list of vertices of any\n"
9828  << "of the sub polylines that represent the boundary to\n"
9829  << "connect.\n\n"
9830  << "This is the left vertex of the current shared boundary\n"
9831  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9832  << shd_bnd_left_vertex[1] << ")\n\n"
9833  << "This is the list of vertices on the destination "
9834  << "boundary\n";
9835  for (unsigned p = 0; p < nsub_poly; p++)
9836  {
9837  error << "Subpolyline #("<< p << ")\n";
9838  poly_to_connect_pt = tmp_vector_subpolylines[p];
9839  const unsigned n_v = poly_to_connect_pt->nvertex();
9840  for (unsigned i = 0; i < n_v; i++)
9841  {
9842  Vector<double> cvertex =
9843  poly_to_connect_pt->vertex_coordinate(i);
9844  error
9845  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
9846  <<cvertex[1]<<")\n";
9847  }
9848  } // for (p < nsub_poly)
9849  throw OomphLibError(
9850  error.str(),
9851  "TriangleMesh::create_shared_polylines_connections()",
9852  OOMPH_EXCEPTION_LOCATION);
9853  } // if (!found_vertex_index)
9854 #endif
9855 
9856  // Create the connection, the left vertex of the current
9857  // shared boundary is connected with the vertex_index-th
9858  // vertex of sub_poly_to_connect-th subpolyline of the
9859  // destination boundary
9861  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
9862 
9863  } // if (!connecting_to_an_overlaped_boundary)
9864  else
9865  {
9866  // We first look on the shared boundaries that overlap
9867  // the internal boundaries and the look for the
9868  // sub-polylines that are not marked as being overlaped
9869  // by shared boundaries
9870 
9871  // The vertex where to store the index to connect
9872  unsigned vertex_index = 0;
9873  // The subpoly number to connect
9874  unsigned sub_poly_to_connect = 0;
9875  // A flag to indicate if the connection was found
9876  bool found_vertex_index = false;
9877 
9878  // Get the shared boundaries id that are overlaping the
9879  // internal boundary
9880  Vector<unsigned> dst_shd_bnd_ids;
9881  get_shared_boundaries_overlapping_internal_boundary(
9882  uconnection_to_the_left, dst_shd_bnd_ids);
9883 
9884  // Get the number of shared polylines that were found to
9885  // overlap the internal boundary
9886  const unsigned n_shd_bnd_overlap_int_bnd =
9887  dst_shd_bnd_ids.size();
9888 
9889  // Loop over the shared boundaries that overlap the
9890  // internal boundary and look for the vertex to connect
9891  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9892  {
9893  // Get the shared polyline
9894  const unsigned new_connection_to_the_left =
9895  dst_shd_bnd_ids[ss];
9896 
9897  // Make sure that the destination polyline is not the
9898  // same as the current shared polyline
9899  if (bound_id != new_connection_to_the_left)
9900  {
9901  // Get the shared polyline that is overlaping the
9902  // internal boundary
9903  poly_to_connect_pt =
9904  boundary_polyline_pt(new_connection_to_the_left);
9905 
9906  if (poly_to_connect_pt != 0)
9907  {
9908  // Look for the vertex number in the destination
9909  // shared polyline
9910  found_vertex_index =
9911  get_connected_vertex_number_on_destination_polyline(
9912  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9913  } // if (poly_to_connect_pt != 0)
9914 
9915  // If we have found the vertex to connect then
9916  // break the loop
9917  if (found_vertex_index)
9918  {
9919  break;
9920  } // if (found_vertex_index)
9921 
9922  } // if (bound_id != new_connection_to_the_left)
9923 
9924  } // for (ss < n_shd_bnd_overlaping_int_bnd)
9925 
9926  // If we have not yet found the vertex then look for it
9927  // in the sub-polylines that are not overlaped by shared
9928  // boundaries
9929  if (!found_vertex_index)
9930  {
9931  // Look for the vertex number to connect on each of
9932  // the subpolyines
9933  for (unsigned isub = 0; isub < nsub_poly; isub++)
9934  {
9935  // Only work with those sub-polylines that are not
9936  // overlaped by shared boundaries
9937  if (!boundary_marked_as_shared_boundary(
9938  uconnection_to_the_left, isub))
9939  {
9940  // Assign the pointer to the sub-polyline
9941  poly_to_connect_pt = tmp_vector_subpolylines[isub];
9942  // Search for the vertex in the current sub-polyline
9943  found_vertex_index =
9944  get_connected_vertex_number_on_destination_polyline(
9945  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9946  // If we have found the vertex to connect then break the
9947  // loop
9948  if (found_vertex_index)
9949  {
9950  // But first save the subpoly number (chunk), that
9951  // will be used to perform the connection
9952  sub_poly_to_connect = isub;
9953  break;
9954  } // if (found_vertex_index)
9955 
9956  } // if (not overlaped by shared boundary)
9957 
9958  } // for (isub < nsub_poly)
9959 
9960  } // if (!found_vertex_index)
9961 
9962 #ifdef PARANOID
9963  // If we could not find the vertex index to connect then
9964  // we are in trouble
9965  if (!found_vertex_index)
9966  {
9967  std::stringstream error;
9968  error
9969  << "The current shared boundary (" << bound_id << ") was "
9970  << "marked to have a connection\nto the left with the "
9971  << "boundary (" << uconnection_to_the_left << ").\n"
9972  << "This last boundary is marked to be overlaped by "
9973  << "shared boundaries\n"
9974  << "The problem is that the left vertex of the current\n"
9975  << "shared boundary is not in the list of vertices of "
9976  << "the\nboundary to connect.\n\n"
9977  << "This is the left vertex of the current shared "
9978  << "boundary\n"
9979  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9980  << shd_bnd_left_vertex[1] << ")\n\n"
9981  << "This is the list of vertices on the destination "
9982  << "boundary (only those subpolylines not marked as "
9983  << "overlaped by\nshared boundaries)\n";
9984  for (unsigned p = 0; p < nsub_poly; p++)
9985  {
9986  if (!boundary_marked_as_shared_boundary(
9987  uconnection_to_the_left, p))
9988  {
9989  error << "Subpolyline #("<< p << ")\n";
9990  poly_to_connect_pt = tmp_vector_subpolylines[p];
9991  const unsigned n_v = poly_to_connect_pt->nvertex();
9992  for (unsigned i = 0; i < n_v; i++)
9993  {
9994  Vector<double> cvertex =
9995  poly_to_connect_pt->vertex_coordinate(i);
9996  error
9997  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
9998  <<cvertex[1]<<")\n";
9999  }
10000  } // Not marked as overlaped
10001  } // for (p < nsub_poly)
10002  error << "\nThis is the list of vertices of the shared "
10003  << "polylines that overlap\nthe internal "
10004  << "boundary\n";
10005  Vector<unsigned> dst_shd_bnd_ids;
10006  get_shared_boundaries_overlapping_internal_boundary(
10007  uconnection_to_the_left, dst_shd_bnd_ids);
10008  const unsigned n_shd_bnd_overlap_int_bnd =
10009  dst_shd_bnd_ids.size();
10010  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10011  {
10012  const unsigned new_connection_to_the_left =
10013  dst_shd_bnd_ids[ss];
10014  poly_to_connect_pt =
10015  boundary_polyline_pt(new_connection_to_the_left);
10016  if (poly_to_connect_pt != 0)
10017  {
10018  const unsigned shd_bnd_id_overlap =
10019  poly_to_connect_pt->boundary_id();
10020  error << "Shared boundary id("
10021  << shd_bnd_id_overlap << ")\n";
10022  const unsigned n_v = poly_to_connect_pt->nvertex();
10023  for (unsigned i = 0; i < n_v; i++)
10024  {
10025  Vector<double> cvertex =
10026  poly_to_connect_pt->vertex_coordinate(i);
10027  error
10028  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
10029  <<cvertex[1]<<")\n";
10030  }
10031  } // if (poly_to_connect_pt != 0)
10032  } // for (ss < n_shd_bnd_overlap_int_bnd)
10033 
10034  throw OomphLibError(
10035  error.str(),
10036  "TriangleMesh::create_shared_polylines_connections()",
10037  OOMPH_EXCEPTION_LOCATION);
10038  } // if (!found_vertex_index)
10039 #endif
10040 
10041  // Create the connection, the left vertex of the current
10042  // shared boundary is connected with the vertex_index-th
10043  // vertex of sub_poly_to_connect-th subpolyline of the
10044  // destination boundary
10046  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10047 
10048  } // else if (!connecting_to_an_overlaped_boundary)
10049 
10050  } // else if (!connecting_to_an_split_boundary)
10051 
10052  } // if (connection_to_the_left != -1)
10053 
10054  // --------------------------------------------------------------
10055  // Connection to the right
10056  if (is_connected_to_the_right)
10057  {
10058  // Get the unsigned version of the bound id to connect to
10059  // the right
10060  const unsigned uconnection_to_the_right =
10061  shd_poly_pt->final_vertex_connected_bnd_id();
10062 
10063  // The pointer to the boundary to connect
10064  TriangleMeshPolyLine *poly_to_connect_pt = 0;
10065 
10066  // Flag to indicate we are trying to connect to an split
10067  // boundary
10068  bool connecting_to_an_split_boundary = false;
10069 
10070  // Flag to indicate we are trying to connecto to an internal
10071  // boundary that is overlaped by a shared boundary
10072  bool connecting_to_an_overlaped_boundary = false;
10073 
10074  // Check if the connection is with itself
10075  if (uconnection_to_the_right == bound_id)
10076  {
10077  // Set the pointer to the polyline to connect
10078  poly_to_connect_pt = shd_poly_pt;
10079  }
10080  else
10081  {
10082  // Get the initial shared boundary ids
10083  const unsigned initial_shd_bnd_id = initial_shared_boundary_id();
10084  // Check if the boundary to connect is a shared polyline
10085  if (uconnection_to_the_right >= initial_shd_bnd_id)
10086  {
10087  // Get the polyline pointer representing the destination
10088  // boundary
10089  poly_to_connect_pt =
10090  boundary_polyline_pt(uconnection_to_the_right);
10091  } // if (uconnection_to_the_left >= initial_shd_bnd_id)
10092  else
10093  {
10094  // If we are going to connect to an original boundary
10095  // verify if the boundary was splitted during the
10096  // distribution process to consider all the chunks
10097  // (sub-polylines) of the boundary
10098  if (boundary_was_splitted(uconnection_to_the_right))
10099  {
10100  connecting_to_an_split_boundary = true;
10101  } // if (boundary_was_splitted(uconnection_to_the_right))
10102 
10103  // If we are going to connect to an original boundary
10104  // verify if the boundary, or any of its chunks is
10105  // marked to be overlapped by a shared boundary, if that
10106  // is the case we first check for connections in the
10107  // shared boundary that overlaps the internal boundary,
10108  // or the chunks, and then check for connections in the
10109  // original boundary
10110  if (connecting_to_an_split_boundary)
10111  {
10112  // Get the number of chucks that represent the
10113  // destination boundary
10114  const unsigned n_sub_poly =
10115  nboundary_subpolylines(uconnection_to_the_right);
10116  // Now loop over the chunks of the destination
10117  // boundary and if any of them is marked to be
10118  // overlaped by a shared boundary then set the flag
10119  // and break the loop
10120  for (unsigned ii =0; ii < n_sub_poly; ii++)
10121  {
10122  if (boundary_marked_as_shared_boundary(
10123  uconnection_to_the_right, ii))
10124  {
10125  // Mark the boundary as being overlaped by a
10126  // shared boundary
10127  connecting_to_an_overlaped_boundary = true;
10128  // Break, no need to look for more overlapings
10129  break;
10130  } // if (boundary_marked_as_shared_boundary(...))
10131  } // for (ii < n_sub_poly)
10132  } // if (connecting_to_an_split_boundary)
10133  else
10134  {
10135  // If not connecting to an split boundary then check
10136  // if the whole destination boundary is overlaped by
10137  // an internal boundary
10138  if (boundary_marked_as_shared_boundary(
10139  uconnection_to_the_right, 0))
10140  {
10141  // Mark the boundary as being overlaped by a shared
10142  // boundary
10143  connecting_to_an_overlaped_boundary = true;
10144  } // if (boundary_marked_as_shared_boundary(...))
10145  } // else if (connecting_to_an_split_boundary)
10146 
10147  // If we are connecting neither to an split boundary nor
10148  // an overlaped boundary then get the pointer to the
10149  // original boundary
10150  if (!(connecting_to_an_split_boundary ||
10151  connecting_to_an_overlaped_boundary))
10152  {
10153  // Get the polyline pointer representing the
10154  // destination boundary
10155  poly_to_connect_pt =
10156  boundary_polyline_pt(uconnection_to_the_right);
10157  } // else if (NOT split, NOT overlaped)
10158  } // else if (uconnection_to_the_right >= initial_shd_bnd_id)
10159 
10160  } // else if (uconnection_to_the_right == bound_id)
10161 
10162 #ifdef PARANOID
10163  // If we are not connecting to an original boundary
10164  // (connecting to the same shared boundary or to another
10165  // shared boundary) then the boundary should not be marked
10166  // as split
10167  if (!connecting_to_an_split_boundary)
10168  {
10169  if (boundary_was_splitted(uconnection_to_the_right))
10170  {
10171  std::stringstream error;
10172  error
10173  << "The current shared boundary (" << bound_id << ") was "
10174  << "marked to have a connection\nto the right with the "
10175  << "boundary (" << uconnection_to_the_right << ").\n"
10176  << "The problem is that the destination boundary (possibly\n"
10177  << "another shared boundary) is marked to be split\n"
10178  << "There should not be split shared boundaries\n\n";
10179  throw OomphLibError(
10180  error.str(),
10181  "TriangleMesh::create_shared_polylines_connections()",
10182  OOMPH_EXCEPTION_LOCATION);
10183  }
10184  } // if (!connecting_to_an_split_boundary)
10185 #endif
10186 
10187  // Now look for the vertex number on the destination
10188  // boundary(ies) -- in case that the boundary was split ---
10189 
10190  // Do not check for same orientation, that was previously
10191  // worked by interchanging the connections boundaries (if
10192  // necessary)
10193 
10194  // Get the right vertex in the shared boundary
10195  Vector<double> shd_bnd_right_vertex =
10196  shd_poly_pt->vertex_coordinate(n_vertex-1);
10197 
10198  // If the boundary was not split then inmediately look for
10199  // the vertex index in the destination boundary
10200  if (!connecting_to_an_split_boundary)
10201  {
10202  // ... check if the boundary is marked to be overlaped by
10203  // a shared boundary
10204  if (!connecting_to_an_overlaped_boundary)
10205  {
10206  // If that is not the case then we can safely look for
10207  // the vertex number on the destination boundar
10208 
10209  unsigned vertex_index = 0;
10210  const bool found_vertex_index =
10211  get_connected_vertex_number_on_destination_polyline(
10212  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10213 
10214  // If we could not find the vertex index to connect then
10215  // we are in trouble
10216  if (!found_vertex_index)
10217  {
10218  std::stringstream error;
10219  error
10220  << "The current shared boundary (" << bound_id << ") was "
10221  << "marked to have a connection\nto the right with the "
10222  << "boundary (" << uconnection_to_the_right << ").\n"
10223  << "The problem is that the right vertex of the current\n"
10224  << "shared boundary is not in the list of vertices of the\n"
10225  << "boundary to connect.\n\n"
10226  << "This is the right vertex of the current shared boundary\n"
10227  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10228  << shd_bnd_right_vertex[1] << ")\n\n"
10229  << "This is the list of vertices on the destination boundary\n";
10230  const unsigned n_v = poly_to_connect_pt->nvertex();
10231  for (unsigned i = 0; i < n_v; i++)
10232  {
10233  Vector<double> cvertex =
10234  poly_to_connect_pt->vertex_coordinate(i);
10235  error
10236  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "<<cvertex[1]<<")\n";
10237  }
10238  throw OomphLibError(
10239  error.str(),
10240  "TriangleMesh::create_shared_polylines_connections()",
10241  OOMPH_EXCEPTION_LOCATION);
10242  } // if (!found_vertex_index)
10243 
10244  // Create the connection, the right vertex of the current
10245  // shared boundary is connected with the vertex_index-th
10246  // vertex on the destination boundary
10247  shd_poly_pt->connect_final_vertex_to_polyline(
10248  poly_to_connect_pt, vertex_index);
10249 
10250  } // if (!connecting_to_an_overlaped_boundary)
10251  else
10252  {
10253  // If the boundary is marked to be overlaped by a shared
10254  // boundary then get that shared boundary and look for
10255  // the connection in that boundary
10256 
10257  // The vertex where to store the index to connect
10258  unsigned vertex_index = 0;
10259  // A flag to indicate if the connection was found
10260  bool found_vertex_index = false;
10261 
10262  // Get the shared boundary id that is overlaping the
10263  // internal boundary
10264  Vector<unsigned> dst_shd_bnd_ids;
10265  get_shared_boundaries_overlapping_internal_boundary(
10266  uconnection_to_the_right, dst_shd_bnd_ids);
10267 
10268  // Get the number of shared polylines that were found to
10269  // overlap the internal boundary
10270  const unsigned n_shd_bnd_overlap_int_bnd =
10271  dst_shd_bnd_ids.size();
10272 
10273  // Loop over the shared boundaries that overlap the
10274  // internal boundary and look for the vertex to connect
10275  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10276  {
10277  // Get the shared polyline
10278  const unsigned new_connection_to_the_right =
10279  dst_shd_bnd_ids[ss];
10280 
10281  // Get the shared polyline that is overlaping the
10282  // internal boundary
10283  poly_to_connect_pt =
10284  boundary_polyline_pt(new_connection_to_the_right);
10285 
10286  if (poly_to_connect_pt!=0)
10287  {
10288  // Look for the vertex number in the destination
10289  // shared polyline
10290  found_vertex_index =
10291  get_connected_vertex_number_on_destination_polyline(
10292  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10293  } // if (poly_to_connect_pt!=0)
10294 
10295  // If we have found the vertex to connect then
10296  // break the loop
10297  if (found_vertex_index)
10298  {
10299  break;
10300  } // if (found_vertex_index)
10301 
10302  } // for (ss < n_shd_bnd_overlaping_int_bnd)
10303 
10304 #ifdef PARANOID
10305  // If we could not find the vertex index to connect then
10306  // we are in trouble
10307  if (!found_vertex_index)
10308  {
10309  std::stringstream error;
10310  error
10311  << "The current shared boundary (" << bound_id << ") was "
10312  << "marked to have a connection\nto the right with the "
10313  << "boundary (" << uconnection_to_the_right << ").\n"
10314  << "This last boundary is marked to be overlaped by "
10315  << "shared boundaries\n"
10316  << "The problem is that the right vertex of the current\n"
10317  << "shared boundary is not in the list of vertices of the\n"
10318  << "boundary to connect.\n\n"
10319  << "This is the right vertex of the current shared boundary\n"
10320  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10321  << shd_bnd_right_vertex[1] << ")\n\n"
10322  << "This is the list of vertices on the destination "
10323  << "boundary\n";
10324  Vector<unsigned> dst_shd_bnd_ids;
10325  get_shared_boundaries_overlapping_internal_boundary(
10326  uconnection_to_the_right, dst_shd_bnd_ids);
10327  const unsigned n_shd_bnd_overlap_int_bnd =
10328  dst_shd_bnd_ids.size();
10329  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10330  {
10331  const unsigned new_connection_to_the_right =
10332  dst_shd_bnd_ids[ss];
10333  poly_to_connect_pt =
10334  boundary_polyline_pt(new_connection_to_the_right);
10335  if (poly_to_connect_pt != 0)
10336  {
10337  const unsigned shd_bnd_id_overlap =
10338  poly_to_connect_pt->boundary_id();
10339  error << "Shared boundary id("
10340  << shd_bnd_id_overlap << ")\n";
10341  const unsigned n_v = poly_to_connect_pt->nvertex();
10342  for (unsigned i = 0; i < n_v; i++)
10343  {
10344  Vector<double> cvertex =
10345  poly_to_connect_pt->vertex_coordinate(i);
10346  error
10347  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
10348  <<cvertex[1]<<")\n";
10349  }
10350  } // if (poly_to_connect_pt != 0)
10351  } // for (ss < n_shd_bnd_overlap_int_bnd)
10352 
10353  throw OomphLibError(
10354  error.str(),
10355  "TriangleMesh::create_shared_polylines_connections()",
10356  OOMPH_EXCEPTION_LOCATION);
10357 
10358  } // if (!found_vertex_index)
10359 #endif
10360 
10361  // Create the connection, the right vertex of the
10362  // current shared boundary is connected with the
10363  // vertex_index-th vertex on the destination boundary
10364  shd_poly_pt->connect_final_vertex_to_polyline(
10365  poly_to_connect_pt, vertex_index);
10366 
10367  } // else if (!connecting_to_an_overlaped_boundary)
10368 
10369  } // if (!connecting_to_an_split_boundary)
10370  else
10371  {
10372  // If the boundary was split then we need to look for the
10373  // vertex in the sub-polylines
10374 
10375  // Get the sub-polylines vector
10376  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
10377  boundary_subpolylines(uconnection_to_the_right);
10378 
10379  // Get the number of sub-polylines
10380  const unsigned nsub_poly = tmp_vector_subpolylines.size();
10381 #ifdef PARANOID
10382  if (nsub_poly <= 1)
10383  {
10384  std::ostringstream error_message;
10385  error_message
10386  <<"The boundary (" << uconnection_to_the_right << ") was "
10387  << "marked to be splitted but\n"
10388  << "there are only ("<<nsub_poly<<") polylines to "
10389  << "represent it.\n";
10390  throw OomphLibError(
10391  error_message.str(),
10392  "TriangleMesh::create_shared_polylines_connections()",
10393  OOMPH_EXCEPTION_LOCATION);
10394  } // if (nsub_poly <= 1)
10395 #endif
10396 
10397  // We need to check if the boundary is marked to be
10398  // overlaped by an internal boundary, if that is the case
10399  // we need to check for each indivual subpolyline, and for
10400  // those overlaped by a shared polyline look for the
10401  // vertex in the shared polyline representation instead of
10402  // the original subpolyline
10403 
10404  // ... check if the boundary is marked to be overlaped by
10405  // a shared boundary
10406  if (!connecting_to_an_overlaped_boundary)
10407  {
10408  // We can work without checking the subpolylines
10409  // individually
10410 
10411  // The vertex where to store the index to connect
10412  unsigned vertex_index = 0;
10413  // The subpoly number to connect
10414  unsigned sub_poly_to_connect = 0;
10415  // A flag to indicate if the connection was found
10416  bool found_vertex_index = false;
10417 
10418  // Look for the vertex number to connect on each of the
10419  // subpolyines
10420  for (unsigned isub = 0; isub < nsub_poly; isub++)
10421  {
10422  // Assign the pointer to the sub-polyline
10423  poly_to_connect_pt = tmp_vector_subpolylines[isub];
10424  // Search for the vertex in the current sub-polyline
10425  found_vertex_index =
10426  get_connected_vertex_number_on_destination_polyline(
10427  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10428  // If we have found the vertex to connect then break the
10429  // loop
10430  if (found_vertex_index)
10431  {
10432  // But first save the subpoly number (chunk), that
10433  // will be used to perform the connection
10434  sub_poly_to_connect = isub;
10435  break;
10436  } // if (found_vertex_index)
10437  } // for (isub < nsub_poly)
10438 
10439 #ifdef PARANOID
10440  // If we could not find the vertex index to connect then
10441  // we are in trouble
10442  if (!found_vertex_index)
10443  {
10444  std::stringstream error;
10445  error
10446  << "The current shared boundary (" << bound_id << ") was "
10447  << "marked to have a connection\nto the right with the "
10448  << "boundary (" << uconnection_to_the_right << ").\n"
10449  << "The problem is that the right vertex of the current\n"
10450  << "shared boundary is not in the list of vertices of any\n"
10451  << "of the sub polylines that represent the boundary to\n"
10452  << "connect.\n\n"
10453  << "This is the right vertex of the current shared boundary\n"
10454  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10455  << shd_bnd_right_vertex[1] << ")\n\n"
10456  << "This is the list of vertices on the destination "
10457  << "boundary\n";
10458  for (unsigned p = 0; p < nsub_poly; p++)
10459  {
10460  error << "Subpolyline #("<< p << ")\n";
10461  poly_to_connect_pt = tmp_vector_subpolylines[p];
10462  const unsigned n_v = poly_to_connect_pt->nvertex();
10463  for (unsigned i = 0; i < n_v; i++)
10464  {
10465  Vector<double> cvertex =
10466  poly_to_connect_pt->vertex_coordinate(i);
10467  error
10468  <<"Vertex #"<<i<<": ("<<cvertex[0]
10469  <<", "<<cvertex[1]<<")\n";
10470  }
10471  } // for (p < nsub_poly)
10472  throw OomphLibError(
10473  error.str(),
10474  "TriangleMesh::create_shared_polylines_connections()",
10475  OOMPH_EXCEPTION_LOCATION);
10476  } // if (!found_vertex_index)
10477 #endif
10478 
10479  // Create the connection, the right vertex of the current
10480  // shared boundary is connected with the vertex_index-th
10481  // vertex of sub_poly_to_connect-th subpolyline of the
10482  // destination boundary
10483  shd_poly_pt->connect_final_vertex_to_polyline(
10484  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10485 
10486  } // if (!connecting_to_an_overlaped_boundary)
10487  else
10488  {
10489  // We first look on the shared boundaries that overlap
10490  // the internal boundaries and the look for the
10491  // sub-polylines that are not marked as being overlaped
10492  // by shared boundaries
10493 
10494  // The vertex where to store the index to connect
10495  unsigned vertex_index = 0;
10496  // The subpoly number to connect
10497  unsigned sub_poly_to_connect = 0;
10498  // A flag to indicate if the connection was found
10499  bool found_vertex_index = false;
10500 
10501  // Get the shared boundaries id that are overlaping the
10502  // internal boundary
10503  Vector<unsigned> dst_shd_bnd_ids;
10504  get_shared_boundaries_overlapping_internal_boundary(
10505  uconnection_to_the_right, dst_shd_bnd_ids);
10506 
10507  // Get the number of shared polylines that were found to
10508  // overlap the internal boundary
10509  const unsigned n_shd_bnd_overlap_int_bnd =
10510  dst_shd_bnd_ids.size();
10511 
10512  // Loop over the shared boundaries that overlap the
10513  // internal boundary and look for the vertex to connect
10514  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10515  {
10516  // Get the shared polyline
10517  const unsigned new_connection_to_the_right =
10518  dst_shd_bnd_ids[ss];
10519 
10520  // Make sure that the destination polyline is not the
10521  // same as the current shared polyline
10522  if (bound_id != new_connection_to_the_right)
10523  {
10524  // Get the shared polyline that is overlaping the
10525  // internal boundary
10526  poly_to_connect_pt =
10527  boundary_polyline_pt(new_connection_to_the_right);
10528 
10529  if (poly_to_connect_pt != 0)
10530  {
10531  // Look for the vertex number in the destination
10532  // shared polyline
10533  found_vertex_index =
10534  get_connected_vertex_number_on_destination_polyline(
10535  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10536  } // if (poly_to_connect_pt != 0)
10537 
10538  // If we have found the vertex to connect then
10539  // break the loop
10540  if (found_vertex_index)
10541  {
10542  break;
10543  } // if (found_vertex_index)
10544 
10545  } // if (bound_id != new_connection_to_the_right)
10546 
10547  } // for (ss < n_shd_bnd_overlaping_int_bnd)
10548 
10549  // If we have not yet found the vertex then look for it
10550  // in the sub-polylines that are not overlaped by shared
10551  // boundaries
10552  if (!found_vertex_index)
10553  {
10554  // Look for the vertex number to connect on each of
10555  // the subpolyines
10556  for (unsigned isub = 0; isub < nsub_poly; isub++)
10557  {
10558  // Only work with those sub-polylines that are not
10559  // overlaped by shared boundaries
10560  if (!boundary_marked_as_shared_boundary(
10561  uconnection_to_the_right, isub))
10562  {
10563  // Assign the pointer to the sub-polyline
10564  poly_to_connect_pt = tmp_vector_subpolylines[isub];
10565  // Search for the vertex in the current sub-polyline
10566  found_vertex_index =
10567  get_connected_vertex_number_on_destination_polyline(
10568  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10569  // If we have found the vertex to connect then break the
10570  // loop
10571  if (found_vertex_index)
10572  {
10573  // But first save the subpoly number (chunk), that
10574  // will be used to perform the connection
10575  sub_poly_to_connect = isub;
10576  break;
10577  } // if (found_vertex_index)
10578 
10579  } // if (not overlaped by shared boundary)
10580 
10581  } // for (isub < nsub_poly)
10582 
10583  } // if (!found_vertex_index)
10584 
10585 #ifdef PARANOID
10586  // If we could not find the vertex index to connect then
10587  // we are in trouble
10588  if (!found_vertex_index)
10589  {
10590  std::stringstream error;
10591  error
10592  << "The current shared boundary (" << bound_id << ") was "
10593  << "marked to have a connection\nto the right with the "
10594  << "boundary (" << uconnection_to_the_right << ").\n"
10595  << "This last boundary is marked to be overlaped by "
10596  << "shared boundaries\n"
10597  << "The problem is that the right vertex of the current\n"
10598  << "shared boundary is not in the list of vertices of "
10599  << "the\nboundary to connect.\n\n"
10600  << "This is the right vertex of the current shared "
10601  << "boundary\n"
10602  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10603  << shd_bnd_right_vertex[1] << ")\n\n"
10604  << "This is the list of vertices on the destination "
10605  << "boundary (only those subpolylines not marked as "
10606  << "overlaped by\nshared boundaries)\n";
10607  for (unsigned p = 0; p < nsub_poly; p++)
10608  {
10609  if (!boundary_marked_as_shared_boundary(
10610  uconnection_to_the_right, p))
10611  {
10612  error << "Subpolyline #("<< p << ")\n";
10613  poly_to_connect_pt = tmp_vector_subpolylines[p];
10614  const unsigned n_v = poly_to_connect_pt->nvertex();
10615  for (unsigned i = 0; i < n_v; i++)
10616  {
10617  Vector<double> cvertex =
10618  poly_to_connect_pt->vertex_coordinate(i);
10619  error
10620  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
10621  <<cvertex[1]<<")\n";
10622  }
10623  } // Not marked as overlaped
10624  } // for (p < nsub_poly)
10625  error << "\nThis is the list of vertices of the shared "
10626  << "polylines that overlap\nthe internal "
10627  << "boundary\n";
10628  Vector<unsigned> dst_shd_bnd_ids;
10629  get_shared_boundaries_overlapping_internal_boundary(
10630  uconnection_to_the_right, dst_shd_bnd_ids);
10631  const unsigned n_shd_bnd_overlap_int_bnd =
10632  dst_shd_bnd_ids.size();
10633  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10634  {
10635  const unsigned new_connection_to_the_right =
10636  dst_shd_bnd_ids[ss];
10637  poly_to_connect_pt =
10638  boundary_polyline_pt(new_connection_to_the_right);
10639  if (poly_to_connect_pt != 0)
10640  {
10641  const unsigned shd_bnd_id_overlap =
10642  poly_to_connect_pt->boundary_id();
10643  error << "Shared boundary id("
10644  << shd_bnd_id_overlap << ")\n";
10645  const unsigned n_v = poly_to_connect_pt->nvertex();
10646  for (unsigned i = 0; i < n_v; i++)
10647  {
10648  Vector<double> cvertex =
10649  poly_to_connect_pt->vertex_coordinate(i);
10650  error
10651  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
10652  <<cvertex[1]<<")\n";
10653  }
10654  } // if (poly_to_connect_pt != 0)
10655  } // for (ss < n_shd_bnd_overlap_int_bnd)
10656 
10657  throw OomphLibError(
10658  error.str(),
10659  "TriangleMesh::create_shared_polylines_connections()",
10660  OOMPH_EXCEPTION_LOCATION);
10661  } // if (!found_vertex_index)
10662 #endif
10663 
10664  // Create the connection, the left vertex of the current
10665  // shared boundary is connected with the vertex_index-th
10666  // vertex of sub_poly_to_connect-th subpolyline of the
10667  // destination boundary
10668  shd_poly_pt->connect_final_vertex_to_polyline(
10669  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10670 
10671  } // else if (!connecting_to_an_overlaped_boundary)
10672 
10673  } // else if (!connecting_to_an_split_boundary)
10674 
10675  } // if (connection_to_the_right != -1)
10676 
10677  } // if (connection_to_the_left != -1 || connection_to_the_right != -1)
10678 
10679  } // for (ipoly < npoly)
10680 
10681  } // for (icurve < ncurves)
10682 
10683  }
10684 
10685  //=======================================================================
10686  // \short Compute the holes left by the halo elements, those adjacent
10687  // to the shared boundaries
10688  //=======================================================================
10689  template<class ELEMENT>
10691  Vector<Vector<double> > &output_holes_coordinates)
10692  {
10693  // Storage for number of processors and current processor
10694  const unsigned n_proc = this->communicator_pt()->nproc();
10695  const unsigned my_rank = this->communicator_pt()->my_rank();
10696 
10697  // Mark those done elements, so we do not repeat any coordinate left
10698  // by repeated halo elements
10699  std::map<FiniteElement*, bool> done_ele;
10700 
10701  // Loop over the processors and get the shared boundaries ids that
10702  // the current processor has with the other processors
10703  for (unsigned iproc = 0; iproc < n_proc; iproc++)
10704  {
10705  // There are shared boundaries only with the other processors
10706  if (iproc != my_rank)
10707  {
10708  // Get the number of shared boundaries with the iproc
10709  const unsigned n_shd_bnd_iproc = nshared_boundaries(my_rank, iproc);
10710 
10711 #ifdef PARANOID
10712  // Get the number of shared boundaries with the iproc, but
10713  // reversing the indexes
10714  const unsigned n_shd_bnd_iproc_rev = nshared_boundaries(iproc, my_rank);
10715  if (n_shd_bnd_iproc != n_shd_bnd_iproc_rev)
10716  {
10717  std::ostringstream error_stream;
10718  error_stream
10719  << "The number of shared boundaries of processor ("
10720  << my_rank << ") with processor(" << iproc << "): ("
10721  << n_shd_bnd_iproc << ")\n"
10722  << "is different from the number of shared boundaries of "
10723  << "processor (" << iproc << ")\nwith processor ("
10724  << my_rank << "): (" << n_shd_bnd_iproc << ")\n\n";
10725  throw OomphLibError(error_stream.str(),
10726  OOMPH_CURRENT_FUNCTION,
10727  OOMPH_EXCEPTION_LOCATION);
10728 
10729  } // if (n_shd_bnd_iproc != n_shd_bnd_iproc_rev)
10730 #endif
10731 
10732  // Loop over the shared boundaries ids
10733  for (unsigned i = 0; i < n_shd_bnd_iproc; i++)
10734  {
10735  // Get the shared boundary id
10736  const unsigned shd_bnd_id = shared_boundaries_ids(my_rank, iproc, i);
10737 
10738  // Get the number of shared boundary elements
10739  const unsigned n_shd_bnd_ele = nshared_boundary_element(shd_bnd_id);
10740 
10741  // Loop over the shared boundary elements
10742  for (unsigned e = 0; e < n_shd_bnd_ele; e++)
10743  {
10744  // Get the shared boundary element
10745  FiniteElement* ele_pt = shared_boundary_element_pt(shd_bnd_id, e);
10746 
10747  // Only work with halo elements
10748  if (ele_pt->is_halo())
10749  {
10750  // If the element has not been visited
10751  if (!done_ele[ele_pt])
10752  {
10753  // Get the number of nodes
10754  const unsigned n_nodes = ele_pt->nnode();
10755 
10756  // Compute the centroid of the element
10757  Vector<double> element_centroid(2, 0.0);
10758  // Loop over the nodes
10759  for (unsigned k = 0; k < n_nodes; k++)
10760  {
10761  Node* tmp_node_pt = ele_pt->node_pt(k);
10762  // Loop over the dimension
10763  for (unsigned d = 0; d < 2; d++)
10764  {
10765  element_centroid[d]+=tmp_node_pt->x(d);
10766  } // for (d < 2)
10767  } // for (k < n_nodes)
10768 
10769  // Average the data
10770  for (unsigned d = 0; d < 2; d++)
10771  {
10772  element_centroid[d] =
10773  element_centroid[d] / (double)n_nodes;
10774  } // for (d < 2)
10775 
10776  // Add the centroid to the output holes
10777  output_holes_coordinates.push_back(element_centroid);
10778 
10779  } // if (!done_ele[ele_pt])
10780 
10781  } // if (ele_pt->is_halo())
10782 
10783  } // for1 (e < n_shd_bnd_ele)
10784 
10785  } // for (i < n_shd_bnd_iproc)
10786 
10787  } // if (iproc != my_rank)
10788 
10789  } // for (iproc < n_proc)
10790 
10791  }
10792 
10793  //======================================================================
10794  // \short Keeps those vertices that define a hole, those that are
10795  // inside closed internal boundaries in the new polygons that define
10796  // the domain. Delete those outside/inside the outer polygons (this
10797  // is required since Triangle can not deal with vertices that define
10798  // holes outside the new outer polygons of the domain)
10799  //======================================================================
10800  template<class ELEMENT>
10802  Vector<TriangleMeshPolygon *> &polygons_pt,
10803  Vector<Vector<double> > &output_holes_coordinates)
10804  {
10805  // General strategy
10806 
10807  // 1) Identify the inner closed boundaries
10808 
10809  // 2) Separate the vertices in three groups
10810 
10811  // --- 2.1) The vertices inside the inner closed boundaries, these
10812  // are not deleted because they define holes
10813 
10814  // --- 2.2) The vertices outside the outer boundaries, these are
10815  // deleted only if they are outside the convex hull defined
10816  // by all the polygons
10817 
10818  // --- 2.3) Any other vertex is deleted
10819 
10820  // Get the number of input holes
10821  const unsigned n_input_holes = output_holes_coordinates.size();
10822 
10823  // Only do something if there are holes
10824  if (n_input_holes == 0)
10825  {
10826  return;
10827  }
10828 
10829  // Get the number of input polygons
10830  const unsigned n_polygons = polygons_pt.size();
10831 
10832  // Store the vertices of all the input polygons
10833  // vertices_polygons[x][ ][ ]: Polygon number
10834  // vertices_polygons[ ][x][ ]: Vertex number
10835  // vertices_polygons[ ][ ][x]: Vertex coordinate
10836  Vector<Vector<Vector<double> > > vertices_polygons(n_polygons);
10837 
10838  // Loop over all the polygons and get the vertices
10839  for (unsigned p = 0; p < n_polygons; p++)
10840  {
10841  // Get the number of polylines associated to the polygon
10842  const unsigned n_polylines = polygons_pt[p]->npolyline();
10843  // Loop over the polylines and get the vertices
10844  for (unsigned pp = 0; pp < n_polylines; pp++)
10845  {
10846  // Get the polyline
10847  const TriangleMeshPolyLine* tmp_poly_pt =
10848  polygons_pt[p]->polyline_pt(pp);
10849  // Get the number of vertices in the polyline
10850  const unsigned n_vertices = tmp_poly_pt->nvertex();
10851  // Loop over the vertices but only add (n_vertices-1) vertices,
10852  // the last vertex of polyline (pp) is the first vertex of
10853  // polyline (pp+1)
10854  for (unsigned v = 0; v < n_vertices-1; v++)
10855  {
10856  // Get the current vertex
10857  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
10858  vertices_polygons[p].push_back(current_vertex);
10859  } // for (v < nvertex)
10860  } // for (p < nouter_polylines)
10861  } // for (p < n_polygons)
10862 
10863  // -------------------------------------------------------------------
10864  // 1) Identify the inner closed boundaries
10865  // -------------------------------------------------------------------
10866 
10867  // A container that indicates if a given polygon should be
10868  // considered as an outer or as an inner polygon. By default all the
10869  // polygons are considered as outer polygons
10870  std::vector<bool> is_outer_polygon(n_polygons, true);
10871 
10872  // We only check for innner polygons if there are more than one
10873  // polygon
10874  if (n_polygons > 1)
10875  {
10876  // Propose an inner polygon, if one of the middle points of its
10877  // edges lies inside any other polygon then the proposed inner
10878  // polygon is marked as an internal polygon
10879 
10880  // Pre-compute the middle points of the edges in the polygons
10881  Vector<Vector<Vector<double> > > polygon_edge_middle_vertex(n_polygons);
10882 
10883  for (unsigned p = 0; p < n_polygons; p++)
10884  {
10885  // Temporary store the vertices of the proposed inner polygon
10886  Vector<Vector<double> > tmp_inner_polygon = vertices_polygons[p];
10887 
10888  // Get the number of vertices in the current proposed inner polygon
10889  const unsigned n_vertices = tmp_inner_polygon.size();
10890 
10891  // Resize with the number of edges in the polygon
10892  polygon_edge_middle_vertex[p].resize(n_vertices-1);
10893 
10894  // Loop over the vertices and compute the middle point in the edge
10895  // that joins each pair of contiguous vertices
10896  for (unsigned e = 0; e < n_vertices - 1; e++)
10897  {
10898  // The dimension
10899  const unsigned dim = 2;
10900  polygon_edge_middle_vertex[p][e].resize(dim);
10901  for (unsigned d = 0; d < dim; d++)
10902  {
10903  polygon_edge_middle_vertex[p][e][d] =
10904  (tmp_inner_polygon[e][d] + tmp_inner_polygon[e+1][d]) / 2.0;
10905  } // for (d < 2)
10906 
10907  } // for (e < n_vertices - 1)
10908 
10909  } // for (p < n_polygons)
10910 
10911  // Loop over the polygons and for every loop propose a different
10912  // inner polygon
10913  for (unsigned idx_inner = 0; idx_inner < n_polygons; idx_inner++)
10914  {
10915  // Flag to indicate that ONE of the middle edge vertices of the
10916  // proposed inner polygon is inside another polygon, this will
10917  // set the proposed inner polygon as an actual inner polygon
10918  bool is_inner_polygon = false;
10919 
10920  // Loop over all the polygons, except the proposed one and check
10921  // if all the middle edges of its edges are inside any other
10922  // polygon
10923  for (unsigned i = 0; i < n_polygons; i++)
10924  {
10925  // Do not check with the polygon itself
10926  if (i != idx_inner)
10927  {
10928  // Get the number of edges of the proposed inner polygon
10929  const unsigned n_edges =
10930  polygon_edge_middle_vertex[idx_inner].size();
10931  // Loop over the middle points in the edges of the current
10932  // proposed inner polygon
10933  for (unsigned e = 0; e < n_edges; e++)
10934  {
10935  // Get the vertex in the current proposed inner polygon
10936  Vector<double> current_vertex =
10937  polygon_edge_middle_vertex[idx_inner][e];
10938  // Check if the current vertex is inside the current i-th
10939  // polygon
10940  const bool is_point_inside =
10941  is_point_inside_polygon_helper(vertices_polygons[i],
10942  current_vertex);
10943 
10944  // If one point is inside then the polygon is inside the
10945  // i-th polygon
10946  if (is_point_inside)
10947  {
10948  // The polygon is an inner polygon
10949  is_inner_polygon = true;
10950  // Break the loop
10951  break;
10952  } // if (is_point_inside)
10953 
10954  } // for (e < n_edges)
10955 
10956  } // if (i != idx_inner)
10957 
10958  // Are all the vertices of the current proposed inner polygon
10959  // inside the i-th polygon
10960  if (is_inner_polygon)
10961  {
10962  // The current proposed inner polygon is an actual inner
10963  // polygon, and is inside the i-th polygon
10964  break;
10965  }
10966 
10967  } // for (i < n_polygons)
10968 
10969  // Is the current proposed inner polygon an actual inner polygon
10970  if (is_inner_polygon)
10971  {
10972  // The current proposed inner polygon is a real inner polygon
10973  is_outer_polygon[idx_inner] = false;
10974  }
10975  else
10976  {
10977  // The current proposed inner polygon IS NOT a real inner
10978  // polygon
10979  is_outer_polygon[idx_inner] = true;
10980  }
10981 
10982  } // for (idx_outer < npolygons)
10983 
10984  } // if (n_polygons > 1)
10985 
10986  // Count the number of outer closed boundaries and inner closed
10987  // boundaries
10988  unsigned n_outer_polygons = 0;
10989  unsigned n_inner_polygons = 0;
10990  // Also get the indexes of the inner polygons
10991  Vector<unsigned> index_inner_polygon;
10992  // Loop over the polygons
10993  for (unsigned i = 0; i < n_polygons; i++)
10994  {
10995  if (is_outer_polygon[i])
10996  {
10997  // Increase the counter for outer polygons
10998  n_outer_polygons++;
10999  }
11000  else
11001  {
11002  // Increase the counter for inner polygons
11003  n_inner_polygons++;
11004  // Store the index of the inner polygon
11005  index_inner_polygon.push_back(i);
11006  }
11007  } // for (i < n_polygons)
11008 
11009  // -------------------------------------------------------------------
11010  // 2) Separate the vertices in three groups
11011 
11012  // --- 2.1) The vertices inside the inner closed boundaries, these are
11013  // not deleted because they define holes
11014 
11015  // --- 2.2) The vertices outside the outer boundaries, these are
11016  // deleted only if they are outside the convex hull defined
11017  // by all the polygons
11018 
11019  // --- 2.3) Any other vertex is deleted
11020  // -------------------------------------------------------------------
11021 
11022  // Keep track of the vertices inside the inner closed boundaries (by
11023  // default all vertices not inside the inner polygons)
11024  std::vector<bool> is_inside_an_inner_polygon(n_input_holes, false);
11025 
11026  // Keep track of the vertices outside the outer closed boundaries
11027  // (by default all the vertices are outside the outer polygons)
11028  std::vector<bool> is_outside_the_outer_polygons(n_input_holes, true);
11029 
11030  // Keep track of the vertices inside the convex hull (by default
11031  // all the vertices are not inside the convex hull)
11032  std::vector<bool> is_inside_the_convex_hull(n_input_holes, false);
11033 
11034  // Mark the vertices inside the inner closed boundaries
11036  vertex_inside_inner_polygon(n_inner_polygons);
11037 
11038  // -------------------------------------------------------------------
11039  // Loop over the inner polygons and find all the vertices inside
11040  // each one
11041  for (unsigned i = 0; i < n_inner_polygons; i++)
11042  {
11043  // Get the vertex of the inner polygon
11044  const unsigned ii = index_inner_polygon[i];
11045  // Loop over the vertices defining holes, mark and store those
11046  // inside the inner polygon
11047  for (unsigned h = 0; h < n_input_holes; h++)
11048  {
11049  // Check if the vertex has not been already marked as inside
11050  // another polygon
11051  if (!is_inside_an_inner_polygon[h])
11052  {
11053  // Check if the hole is inside the current inner polygon
11054  const bool is_inside_polygon =
11055  is_point_inside_polygon_helper(vertices_polygons[ii],
11056  output_holes_coordinates[h]);
11057 
11058  // If the vertex is inside the current inner polygon then mark
11059  // it and associate the vertices to the current inner polygon
11060  if (is_inside_polygon)
11061  {
11062  // Set as inside an inner polygon
11063  is_inside_an_inner_polygon[h] = true;
11064  // Associate the vertex to the current inner polygon
11065  vertex_inside_inner_polygon[i].
11066  push_back(output_holes_coordinates[h]);
11067  } // if (is_inside_polygon)
11068 
11069  } // if (!is_inside_an_inner_polygon[h])
11070 
11071  } // for (h < n_input_holes)
11072 
11073  } // for (i < n_polygons)
11074 
11075  // -------------------------------------------------------------------
11076  // Loop over the vertices defining holes and mark those as outside the
11077  // outer polygons
11078  for (unsigned h = 0; h < n_input_holes; h++)
11079  {
11080  // Check if the vertex has not been already marked as inside
11081  // another polygon
11082  if (!is_inside_an_inner_polygon[h])
11083  {
11084  // Loop over the polygons and check if the vertex is outside ALL
11085  // the outer polygons
11086  for (unsigned i = 0; i < n_polygons; i++)
11087  {
11088  // Only work with outer polygons
11089  if (is_outer_polygon[i])
11090  {
11091  // Check if the hole is inside the current outer polygon
11092  const bool is_inside_polygon =
11093  is_point_inside_polygon_helper(vertices_polygons[i],
11094  output_holes_coordinates[h]);
11095 
11096  // If the vertex is inside the current outer polygon then
11097  // mark it and break the loop (it is not outside ALL the
11098  // polygons)
11099  if (is_inside_polygon)
11100  {
11101  // Set as inside an outer polygon
11102  is_outside_the_outer_polygons[h] = false;
11103  // Break the loop
11104  break;
11105  } // if (is_inside_polygon)
11106 
11107  } // if (is_outer_polygon[i])
11108 
11109  } // for (i < n_polygons)
11110 
11111  } // if (!is_inside_an_inner_polygon[h])
11112  else
11113  {
11114  // If the vertex is inside an inner polygon then it is inside an
11115  // outer polygon
11116  is_outside_the_outer_polygons[h] = false;
11117  } // else if (!is_inside_an_inner_polygon[h])
11118 
11119  } // for (h < n_input_holes)
11120 
11121  // -------------------------------------------------------------------
11122  // Compute the convex hull Create the data structure
11123  std::vector<Point> input_vertices_convex_hull;
11124  // Copy ALL the vertices of the polygons
11125  // Loop over the polygons
11126  for (unsigned p = 0; p < n_polygons; p++)
11127  {
11128  // Get the number of vertices
11129  const unsigned n_vertices = vertices_polygons[p].size();
11130  // Loop over the vertices in the polygon
11131  for (unsigned v = 0; v < n_vertices; v++)
11132  {
11133  // Create a new "Point" to store in the input vertices
11134  Point point;
11135  // Assign the values to the "Point"
11136  point.x = vertices_polygons[p][v][0];
11137  point.y = vertices_polygons[p][v][1];
11138  // Add the "Point" to the input vertices
11139  input_vertices_convex_hull.push_back(point);
11140  } // for (v < n_vertices)
11141  } // for (p < n_polygons)
11142 
11143  // Compute the convex hull
11144  std::vector<Point> output_vertices_convex_hull =
11145  convex_hull(input_vertices_convex_hull);
11146 
11147  // Get the number of vertices in the convex hull
11148  const unsigned n_vertices_convex_hull = output_vertices_convex_hull.size();
11149 
11150  // Copy the output to the used data structures
11151  Vector<Vector<double> > vertices_convex_hull(n_vertices_convex_hull);
11152  for (unsigned i = 0; i < n_vertices_convex_hull; i++)
11153  {
11154  // Resize the data structure
11155  vertices_convex_hull[i].resize(2);
11156  // Copy the data
11157  vertices_convex_hull[i][0] = output_vertices_convex_hull[i].x;
11158  vertices_convex_hull[i][1] = output_vertices_convex_hull[i].y;
11159  } // for (i < n_vertices_convex_hull)
11160 
11161  // Loop over the vertices defining holes, work only with those
11162  // outside ALL the outer boundaries and mark those inside the convex
11163  // hull
11164  for (unsigned h = 0; h < n_input_holes; h++)
11165  {
11166  // Only work with those outside ALL the outer polygons
11167  if (is_outside_the_outer_polygons[h])
11168  {
11169  // Check if the hole is inside the convex hull
11170  const bool is_inside_convex_hull =
11171  is_point_inside_polygon_helper(vertices_convex_hull,
11172  output_holes_coordinates[h]);
11173 
11174  // If the vertex is inside the convex hull then mark it
11175  if (is_inside_convex_hull)
11176  {
11177  // Set as inside the convex hull
11178  is_inside_the_convex_hull[h] = true;
11179  } // if (is_inside_convex_hull)
11180 
11181  } // if (is_outside_the_outer_polygons[h])
11182  else
11183  {
11184  // Any vertex inside any outer polygon is inside the convex hull
11185  is_inside_the_convex_hull[h] = true;
11186  } // else if (is_outside_the_outer_polygons[h])
11187 
11188  } // for (h < n_input_holes)
11189 
11190  // Store the output holes, only (those inside an inner polygon) OR
11191  // (those outside ALL the polygons AND inside the convex hull)
11192  Vector<Vector<double> > hole_kept;
11193  for (unsigned h = 0; h < n_input_holes; h++)
11194  {
11195  // Check if the hole should be kept
11196  if ((is_inside_an_inner_polygon[h]) ||
11197  (is_outside_the_outer_polygons[h] && is_inside_the_convex_hull[h]))
11198  {
11199  // Copy the hole information
11200  hole_kept.push_back(output_holes_coordinates[h]);
11201  } // if (keep_hole[h])
11202  } // for (h < n_input_holes)
11203 
11204  // Clear the previous storage
11205  output_holes_coordinates.clear();
11206  // Set the output holes
11207  output_holes_coordinates = hole_kept;
11208 
11209  }
11210 
11211  //======================================================================
11212  // \short Sorts the polylines so they be contiguous and then we can
11213  // create a closed or open curve from them
11214  //======================================================================
11215  template<class ELEMENT>
11218  &unsorted_polylines_pt,
11220  &sorted_polylines_pt)
11221  {
11222  unsigned n_unsorted_polylines = unsorted_polylines_pt.size();
11223  unsigned n_sorted_polylines = 0;
11224  unsigned curves_index = 0;
11225 
11226  // Map to know which polyline has been already sorted
11227  std::map<TriangleMeshPolyLine*, bool> done_polyline;
11228 
11229  do
11230  {
11231  // Create the list that stores the polylines and allows to introduce
11232  // polylines to the left and to the right
11233  std::list<TriangleMeshPolyLine*> sorted_polyline_list_pt;
11234  bool changes = false;
11235 
11236  // Create pointers to the left and right "side" of the sorted list of
11237  // new created TriangleMeshPolyLines
11238  TriangleMeshPolyLine* left_pt = 0;
11239  TriangleMeshPolyLine* right_pt = 0;
11240 
11241  // 1) Take the first non done polyline on the unsorted list of polylines
11242  unsigned pp = 0;
11243  bool found_root_polyline = false;
11244  while (pp < n_unsorted_polylines && !found_root_polyline)
11245  {
11246  if (!done_polyline[unsorted_polylines_pt[pp]])
11247  {found_root_polyline = true;}
11248  else
11249  {pp++;}
11250  }
11251 
11252  // Check if there are polylines to be sorted
11253  if (pp < n_unsorted_polylines)
11254  {
11255  // 2) Mark the polyline as done
11256  left_pt = right_pt = unsorted_polylines_pt[pp];
11257  done_polyline[left_pt] = true;
11258  // Increment the number of sorted polylines
11259  n_sorted_polylines++;
11260 
11261  // 3) Add this polyline to the sorted list and use it as root
11262  // to sort the other polylines
11263  sorted_polyline_list_pt.push_back(left_pt);
11264 
11265  do {
11266 
11267  changes = false;
11268 
11269  Vector<double> left_vertex(2);
11270  Vector<double> right_vertex(2);
11271 
11272  left_pt->initial_vertex_coordinate(left_vertex);
11273  right_pt->final_vertex_coordinate(right_vertex);
11274 
11275  for (unsigned i = pp+1; i < n_unsorted_polylines; i++)
11276  {
11277  TriangleMeshPolyLine *current_polyline_pt =
11278  unsorted_polylines_pt[i];
11279  if (!done_polyline[current_polyline_pt])
11280  {
11281  Vector<double> initial_vertex(2);
11282  Vector<double> final_vertex(2);
11283  current_polyline_pt->initial_vertex_coordinate(initial_vertex);
11284  current_polyline_pt->final_vertex_coordinate(final_vertex);
11285 
11286  // Compare if the current polyline should go to the left or
11287  // to the right on the sorted polyline list
11288 
11289  // Go to the left
11290  if (left_vertex == final_vertex)
11291  {
11292  left_pt = current_polyline_pt;
11293  sorted_polyline_list_pt.push_front(left_pt);
11294  done_polyline[left_pt] = true;
11295  n_sorted_polylines++;
11296 
11297  // We have added one more polyline, go for another round
11298  changes = true;
11299  }
11300  // Go to the right
11301  else if (right_vertex == initial_vertex)
11302  {
11303  right_pt = current_polyline_pt;
11304  sorted_polyline_list_pt.push_back(right_pt);
11305  done_polyline[right_pt] = true;
11306  n_sorted_polylines++;
11307 
11308  // We have added one more polyline, go for another round
11309  changes = true;
11310  }
11311  // Go to the left but it is reversed
11312  else if (left_vertex == initial_vertex)
11313  {
11314  current_polyline_pt->reverse();
11315  left_pt = current_polyline_pt;
11316  sorted_polyline_list_pt.push_front(left_pt);
11317  done_polyline[left_pt] = true;
11318  n_sorted_polylines++;
11319 
11320  // We have added one more polyline, go for another round
11321  changes = true;
11322  }
11323  // Go to the right but it is reversed
11324  else if (right_vertex == final_vertex)
11325  {
11326  current_polyline_pt->reverse();
11327  right_pt = current_polyline_pt;
11328  sorted_polyline_list_pt.push_back(right_pt);
11329  done_polyline[right_pt] = true;
11330  n_sorted_polylines++;
11331 
11332  // We have added one more polyline, go for another round
11333  changes = true;
11334  }
11335  } // if (!done_polyline[current_polyline_pt])
11336  if (changes) {break;}
11337  } // for (i < n_unsorted_polylines)
11338  }while(changes);
11339 
11340  } // if (pp < n_unsorted_polylines)
11341  else
11342  {
11343  // All the polylines are now on the sorted list of polylines
11344 #ifdef PARANOID
11345  // This case comes when it was not possible to find a root polyline
11346  // since all of them are marked as done but the number of sorted and
11347  // unsorted polylines is not the same
11348  if (!found_root_polyline)
11349  {
11350  std::stringstream err;
11351  err << "It was not possible to find a root polyline to sort the "
11352  << "others around it.\nThe number of unsorted and sorted "
11353  << "polylines is different, it means that\nnot all the "
11354  << "polylines have been sorted.\n"
11355  << "Found root polyline: ("<<found_root_polyline<<")\n"
11356  << "Sorted polylines: ("<<n_sorted_polylines<<")\n"
11357  << "Unsorted polylines: ("<<n_unsorted_polylines<<")\n";
11358  throw OomphLibError(err.str(),"TriangleMesh::sort_polylines_helper()",
11359  OOMPH_EXCEPTION_LOCATION);
11360  }
11361 #endif
11362  }
11363 
11364  // Create the storage for the new sorted polylines and copy them on the
11365  // vector structure for sorted polylines
11366  unsigned n_sorted_polyline_on_list = sorted_polyline_list_pt.size();
11367 
11368  // Create the temporal vector that stores the sorted polylines
11370  tmp_sorted_polylines(n_sorted_polyline_on_list);
11371  unsigned counter = 0;
11372 
11373  std::list<TriangleMeshPolyLine*>::iterator it_polyline;
11374  for (it_polyline = sorted_polyline_list_pt.begin();
11375  it_polyline != sorted_polyline_list_pt.end();
11376  it_polyline++)
11377  {
11378  tmp_sorted_polylines[counter] = *it_polyline;
11379  counter++;
11380  }
11381 
11382  sorted_polylines_pt.push_back(tmp_sorted_polylines);
11383 
11384  ++curves_index;
11385 
11386  }while(n_sorted_polylines < n_unsorted_polylines);
11387 
11388 #ifdef PARANOID
11389  // Verify that the number of polylines on the sorted list is the same
11390  // as the number of polylines on the unsorted list
11391  if (n_sorted_polylines != n_unsorted_polylines)
11392  {
11393  std::stringstream err;
11394  err << "The number of polylines on the unsorted and sorted vectors"
11395  << " is different,\n"
11396  << "it means that not all the polylines have been sorted.\n"
11397  << "Sorted polylines: "<<n_sorted_polylines
11398  << "\nUnsorted polylines: "<<n_unsorted_polylines;
11399  throw OomphLibError(err.str(), "TriangleMesh::sort_polylines_helper()",
11400  OOMPH_EXCEPTION_LOCATION);
11401  }
11402 #endif
11403 
11404  }
11405 
11406  //======================================================================
11407  // \short Creates the shared boundaries
11408  //======================================================================
11409  template<class ELEMENT>
11411  OomphCommunicator* comm_pt,
11412  const Vector<unsigned> &element_domain,
11413  const Vector<GeneralisedElement*> &backed_up_el_pt,
11414  const Vector<FiniteElement*> &backed_up_f_el_pt,
11415  std::map<Data*,std::set<unsigned> > &processors_associated_with_data,
11416  const bool& overrule_keep_as_halo_element_status)
11417  {
11418  // Storage for number of processors and current processor
11419  const unsigned nproc = comm_pt->nproc();
11420  const unsigned my_rank = comm_pt->my_rank();
11421 
11422  // Storage for all the halo elements on all processors
11423  // halo_element[iproc][jproc][ele_number]
11424  // Stores the "ele_number"-th halo element of processor "iproc" with
11425  // processor "jproc"
11426  Vector<Vector<Vector<GeneralisedElement*> > > halo_element_pt(nproc);
11427  // Create complete storage for the halo_element_pt container
11428  for (unsigned iproc = 0; iproc < nproc; iproc++)
11429  {halo_element_pt[iproc].resize(nproc);}
11430 
11431  // Store the global index of the element, used to check for possible
11432  // misclassification of halo elements in the above container
11433  // (halo_element_pt)
11434  std::map<GeneralisedElement*, unsigned> element_to_global_index;
11435 
11436  // Get the halo elements on all processors
11437  this->get_halo_elements_on_all_procs(nproc, element_domain,
11438  backed_up_el_pt,
11439  processors_associated_with_data,
11440  overrule_keep_as_halo_element_status,
11441  element_to_global_index,
11442  halo_element_pt);
11443 
11444  // Resize the shared polylines container
11445  flush_shared_boundary_polyline_pt();
11446  Shared_boundary_polyline_pt.resize(nproc);
11447 
11448  // Create a set that store only the elements that will be kept in
11449  // the processor as nonhalo element, those whose element_domains is
11450  // equal to my_rank. This set is used when creating the shared
11451  // polylines and identify the connections to the original boundaries
11452  std::set<FiniteElement*> element_in_processor_pt;
11453  const unsigned n_ele = backed_up_f_el_pt.size();
11454  for (unsigned e = 0; e < n_ele; e++)
11455  {
11456  if (element_domain[e] == my_rank)
11457  {
11458  element_in_processor_pt.insert(backed_up_f_el_pt[e]);
11459  } // if (element_domain[e] == my_rank)
11460  } // for (e < n_elex)
11461 
11462  // Look for elements edges that may lie on internal boundaries
11463  // If that is the case then relate the face with the boundary on
11464  // which it lies
11465  std::map<std::pair<Node*,Node*>, unsigned> elements_edges_on_boundary;
11466  this->get_element_edges_on_boundary(elements_edges_on_boundary);
11467 
11468  // Now we have all the halo elements on all processors. Use the
11469  // edges shared by the halo elements to create the shared boundaries.
11470  this->create_polylines_from_halo_elements_helper(element_domain,
11471  element_to_global_index,
11472  element_in_processor_pt,
11473  halo_element_pt,
11474  elements_edges_on_boundary,
11475  Shared_boundary_polyline_pt);
11476 
11477  }
11478 
11479  //======================================================================
11480  /// \short Creates the halo elements on all processors
11481  /// Gets the halo elements on all processors, these elements are then used
11482  /// on the function that computes the shared boundaries among the processors
11483  //======================================================================
11484  template<class ELEMENT>
11486  const unsigned &nproc, const Vector<unsigned> &element_domain,
11487  const Vector<GeneralisedElement*> &backed_up_el_pt,
11488  std::map<Data*,std::set<unsigned> > &processors_associated_with_data,
11489  const bool&overrule_keep_as_halo_element_status,
11490  std::map<GeneralisedElement*, unsigned> &element_to_global_index,
11491  Vector<Vector<Vector<GeneralisedElement*> > > &output_halo_elements_pt)
11492  {
11493  const unsigned n_ele = backed_up_el_pt.size();
11494 
11495  // Loop over all the processors
11496  for (unsigned iproc = 0; iproc < nproc; iproc++)
11497  {
11498  // Boolean to know which elements has been already added to the
11499  // halo scheme on "iproc" processor
11500  Vector<std::map<GeneralisedElement*, bool> > already_added(nproc);
11501 
11502  // Loop over all backed up elements
11503  for (unsigned e=0;e<n_ele;e++)
11504  {
11505  // Get element and its domain
11506  GeneralisedElement* el_pt=backed_up_el_pt[e];
11507  unsigned el_domain=element_domain[e];
11508 
11509  // If element is NOT located on "iproc" processor then check if it is
11510  // halo with "el_domain" processor
11511  if (el_domain!=iproc)
11512  {
11513  // If this current mesh has been told to keep all elements as halos,
11514  // OR the element itself knows that it must be kept then
11515  // keep it
11516  if ((this->Keep_all_elements_as_halos) ||
11517  (el_pt->must_be_kept_as_halo()))
11518  {
11519  if (!overrule_keep_as_halo_element_status)
11520  {
11521  // Add as halo element whose non-halo counterpart is
11522  // located on processor "el_domain"
11523  if (!already_added[el_domain][el_pt])
11524  {
11525  output_halo_elements_pt[iproc][el_domain].push_back(el_pt);
11526  already_added[el_domain][el_pt] = true;
11527  element_to_global_index[el_pt] = e;
11528  }
11529  }
11530  }
11531  // Otherwise: Is one of the nodes associated with other processor?
11532  else
11533  {
11534  //Can only have nodes if this is a finite element
11535  FiniteElement* finite_el_pt = dynamic_cast<FiniteElement*>(el_pt);
11536  if(finite_el_pt!=0)
11537  {
11538  unsigned n_node = finite_el_pt->nnode();
11539  for (unsigned n=0;n<n_node;n++)
11540  {
11541  Node* nod_pt=finite_el_pt->node_pt(n);
11542 
11543  // Keep element?
11544  std::set<unsigned>::iterator it =
11545  processors_associated_with_data[nod_pt].find(iproc);
11546  if (it!=processors_associated_with_data[nod_pt].end())
11547  {
11548  // Add as root halo element whose non-halo counterpart is
11549  // located on processor "el_domain"
11550  if (!already_added[el_domain][el_pt])
11551  {
11552  output_halo_elements_pt[iproc][el_domain].push_back(el_pt);
11553  already_added[el_domain][el_pt] = true;
11554  element_to_global_index[el_pt] = e;
11555  }
11556  // Now break out of loop over nodes
11557  break;
11558  } // if (it!=processors_associated_with_data[nod_pt].end())
11559  } // for (n < n_node)
11560  } // if (finite_el_pt!=0)
11561  } // else (this->Keep_all_elements_as_halos)
11562  } // if (el_domain!=iproc)
11563  } // for (e < nele)
11564  } // for (iproc < nproc)
11565 
11566  }
11567 
11568  //====================================================================
11569  // \short Get the element edges (pair of nodes, edges) that lie
11570  // on a boundary (used to mark shared boundaries that lie on
11571  // internal boundaries)
11572  //====================================================================
11573  template <class ELEMENT>
11575  std::map<std::pair<Node*,Node*>, unsigned> &element_edges_on_boundary)
11576  {
11577  // The number of original boundaries
11578  const unsigned nbound = this->nboundary();
11579  // Loop over the boundaries
11580  for (unsigned b = 0; b < nbound; b++)
11581  {
11582  // Keep track of the pair of nodes done
11583  std::map<std::pair<Node*, Node*>, bool> edge_done;
11584  // Get the number of elements on the boundary
11585  const unsigned nbound_ele = this->nboundary_element(b);
11586  for (unsigned e = 0; e < nbound_ele; e++)
11587  {
11588  // Get the boundary bulk element
11589  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
11590  // Get the face index
11591  int face_index = this->face_index_at_boundary(b, e);
11592  // Create the face element
11593  FiniteElement* face_ele_pt =
11594  new DummyFaceElement<ELEMENT> (bulk_ele_pt, face_index);
11595  // Get the number of nodes on the face element
11596  const unsigned nnodes = face_ele_pt->nnode();
11597  // Get the first and last node
11598  Node* first_node_pt = face_ele_pt->node_pt(0);
11599  Node* last_node_pt = face_ele_pt->node_pt(nnodes-1);
11600 
11601  // Create the pair to store the nodes
11602  std::pair<Node*,Node*> edge =
11603  std::make_pair(first_node_pt, last_node_pt);
11604 
11605  // Has the edge been included
11606  if (!edge_done[edge])
11607  {
11608  // Mark the edge as done
11609  edge_done[edge] = true;
11610 
11611  // Create the reversed version and mark it as done too
11612  std::pair<Node*,Node*> inv_edge =
11613  std::make_pair(last_node_pt, first_node_pt);
11614 
11615  // Mark the reversed edge as done
11616  edge_done[inv_edge] = true;
11617 
11618  // Mark the edge to belong to boundary b
11619  element_edges_on_boundary[edge] = b;
11620  } // if (!edge_done[edge])
11621 
11622  // Free the memory allocated for the face element
11623  delete face_ele_pt;
11624  face_ele_pt = 0;
11625 
11626  } // for (e < nbound_ele)
11627 
11628  } // for (b < nbound)
11629 
11630  }
11631 
11632  // ======================================================================
11633  // \short Creates polylines from the intersection of halo elements on
11634  // all processors. The new polylines define the shared boundaries in
11635  // the domain This method computes the polylines on ALL processors,
11636  // that is why the three dimensions in the structure
11637  // output_polylines_pt[iproc][ncurve][npolyline]
11638  // ======================================================================
11639  template<class ELEMENT>
11641  const Vector<unsigned> &element_domain,
11642  std::map<GeneralisedElement*, unsigned> &element_to_global_index,
11643  std::set<FiniteElement*> &element_in_processor_pt,
11644  Vector<Vector<Vector<GeneralisedElement*> > > &input_halo_elements,
11645  std::map<std::pair<Node*,Node*>, unsigned> &elements_edges_on_boundary,
11646  Vector<Vector<Vector<TriangleMeshPolyLine *> > > &output_polylines_pt)
11647  {
11648  const unsigned nproc = this->communicator_pt()->nproc();
11649  const unsigned my_rank = this->communicator_pt()->my_rank();
11650 
11651  // ---------------------------------------------------------------
11652  // Get the edges shared between each pair of processors
11653  // ---------------------------------------------------------------
11654 
11655  // Storage for the edges (pair of nodes) shared between a pair of
11656  // processors
11658 
11659  // Each edge is associated to two elements, a haloi (halo element
11660  // in processors i) and a haloj (halo element in processors j)
11661  Vector<Vector<Vector<Vector<FiniteElement*> > > > edge_element_pt(nproc);
11662 
11663  // Each edge is associated to two elements, a haloi and a haloj,
11664  // the edge was created from a given face from each element, the
11665  // haloi face is stored at [0], the haloj face is stored at [1]
11666  Vector<Vector<Vector<Vector<int> > > > edge_element_face(nproc);
11667 
11668  // Store the possible internal boundary id associated to each edge
11669  // (-1 if there is no association). Some edges may overlap an
11670  // internal boundary (and only internal boundaries)
11671  Vector<Vector<Vector<int> > > edge_boundary(nproc);
11672 
11673  // Mark those edges (pair of nodes overlapped by a shared boundary)
11674  std::map<std::pair<Node*,Node*>, bool> overlapped_edge;
11675 
11676  // Resize the containers, they store info. for each pair of
11677  // processors
11678 
11679  // First resize the global container
11680  Shared_boundaries_ids.resize(nproc);
11681  for (unsigned j = 0 ; j < nproc; j++)
11682  {
11683  edges[j].resize(nproc);
11684  edge_element_pt[j].resize(nproc);
11685  edge_element_face[j].resize(nproc);
11686  edge_boundary[j].resize(nproc);
11687 
11688  // Resize the global container for shared boundaries ids
11689  Shared_boundaries_ids[j].resize(nproc);
11690 
11691  } // for (j < nproc)
11692 
11693  // Take the halo elements of processor "iproc" and compare their
11694  // edges with halo elements of other processors (except itself)
11695  for (unsigned iproc = 0; iproc < nproc; iproc++)
11696  {
11697  // Take the halo elements of processor iproc and compare with
11698  // other processors
11699  // Start from the iproc + 1,
11700  // 1) To avoid comparing with itself,
11701  // 2) To avoid generation of repeated boundaries
11702  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
11703  {
11704  // **************************************************************
11705  // FIRST PART
11706  // 1) Get the halo elements of processor "iproc" with processor
11707  // "jproc"
11708  // 2) Get the halo elements of processor "jproc" with processor
11709  // "iproc"
11710  // 3) Compare their edges and those that match are the ones that
11711  // define the shared boundaries
11712  // **************************************************************
11713 
11714  // Storage for halo elements
11715  Vector<GeneralisedElement*> halo_elements_iproc_with_jproc;
11716  Vector<GeneralisedElement*> halo_elements_jproc_with_iproc;
11717 
11718  // Get the halo elements of "iproc" with "jproc"
11719  halo_elements_iproc_with_jproc = input_halo_elements[iproc][jproc];
11720 
11721  // If there are halo elements then there are shared boundaries
11722  const unsigned nhalo_elements_iproc_with_jproc =
11723  halo_elements_iproc_with_jproc.size();
11724 // DEBP(nhalo_elements_iproc_with_jproc);
11725  if (nhalo_elements_iproc_with_jproc > 0)
11726  {
11727  // Get the halo elements of "jproc" with "iproc"
11728  halo_elements_jproc_with_iproc = input_halo_elements[jproc][iproc];
11729 
11730  // If there are halo elements then there are shared
11731  // boundaries
11732  const unsigned nhalo_elements_jproc_with_iproc =
11733  halo_elements_jproc_with_iproc.size();
11734 // DEBP(nhalo_elements_jproc_with_iproc);
11735 #ifdef PARANOID
11736  if (nhalo_elements_jproc_with_iproc == 0)
11737  {
11738  // If there are halo elements of iproc with jproc there
11739  // MUST be halo elements on the other way round, not
11740  // necessary the same but at least one
11741  std::stringstream err;
11742  err <<"There are no halo elements from processor ("<<jproc<<") "
11743  <<"with processor ("<<iproc<<").\n"
11744  <<"This is strange since there are halo elements from "
11745  <<"processor ("<<iproc<<") with processor ("<<jproc<<").\n"
11746  <<"Number of halo elements from ("<<iproc<<") to ("
11747  <<jproc<<") : ("<< nhalo_elements_iproc_with_jproc<<")\n"
11748  <<"Number of halo elements from ("<<jproc<<") to ("
11749  <<iproc<<") : ("<< nhalo_elements_jproc_with_iproc<<")\n";
11750  throw OomphLibError(err.str(),
11751  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11752  OOMPH_EXCEPTION_LOCATION);
11753  }
11754 #endif
11755  // The edges are defined as pair of nodes
11756  Vector<Node*> halo_edges_iproc;
11757  unsigned halo_edges_counter_iproc = 0;
11758  Vector<Node*> halo_edges_jproc;
11759  unsigned halo_edges_counter_jproc = 0;
11760 
11761  // Map to associate the edge with the element used to create it
11762  std::map<std::pair<Node*,Node*>,FiniteElement*> edgesi_to_element_pt;
11763 
11764  // Map to associated the edge with the face number of the
11765  // element that created it
11766  std::map<std::pair<std::pair<Node*,Node*>, FiniteElement*>, int>
11767  edgesi_element_pt_to_face_index;
11768 
11769  // Map to associate the edge with the element used to create it
11770  std::map<std::pair<Node*,Node*>,FiniteElement*> edgesj_to_element_pt;
11771 
11772  // Map to associated the edge with the face number of the
11773  // element that created it
11774  std::map<std::pair<std::pair<Node*,Node*>, FiniteElement*>, int>
11775  edgesj_element_pt_to_face_index;
11776 
11777  // **************************************************************
11778  // 1.1) Store the edges of the "iproc" halo elements
11779  // **************************************************************
11780  // Go throught halo elements on "iproc" processor
11781  for (unsigned ih = 0; ih < nhalo_elements_iproc_with_jproc; ih++)
11782  {
11783 #ifdef PARANOID
11784  unsigned e =
11785  element_to_global_index[halo_elements_iproc_with_jproc[ih]];
11786  // Only work with halo elements inside the "jproc" processor
11787  if (element_domain[e] != jproc)
11788  {
11789  // There was a problem on the ihalo-jhalo classification
11790  std::stringstream err;
11791  err << "There was a problem on the ihalo-jhalo classification.\n"
11792  << "One of the elements, (the one with the ("<<e<<")-th "
11793  << "index ) is not on the ("<<jproc<<")-th processor\n"
11794  << "but it was stored as a halo element of processor ("
11795  << iproc<<") with processor ("<<jproc<<").\n";
11796  throw OomphLibError(
11797  err.str(),
11798  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11799  OOMPH_EXCEPTION_LOCATION);
11800  }
11801 #endif
11802 
11803  FiniteElement* el_pt =
11804  dynamic_cast<FiniteElement*>(halo_elements_iproc_with_jproc[ih]);
11805 
11806  if (el_pt==0)
11807  {
11808  std::stringstream err;
11809  err << "The halo element ("<<ih<<") could not be casted to the "
11810  << "FiniteElement type.\n";
11811  throw OomphLibError(
11812  err.str(),
11813  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11814  OOMPH_EXCEPTION_LOCATION);
11815  }
11816 
11817 #ifdef PARANOID
11818  // Number of nodes on this element
11819  const unsigned n_nodes = el_pt->nnode();
11820 
11821  // The number of nodes on every element should be at least
11822  // three since we are going to work with the cornes nodes,
11823  // the ones with index 0, 1 and 2
11824  if (n_nodes<3)
11825  {
11826  std::stringstream err;
11827  err << "The number of nodes of the "<<ih<<"-th halo element is"
11828  << " ("<< n_nodes << ").\nWe can not work with triangle "
11829  << "elements with less than three nodes\n";
11830  throw OomphLibError(err.str(),
11831  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11832  OOMPH_EXCEPTION_LOCATION);
11833  }
11834 #endif
11835 
11836  // Get the corner nodes, the first three nodes
11837  Node *first_node_pt = el_pt->node_pt(0);
11838  Node *second_node_pt = el_pt->node_pt(1);
11839  Node *third_node_pt = el_pt->node_pt(2);
11840 
11841  // Store the edges
11842  halo_edges_iproc.push_back(first_node_pt);
11843  halo_edges_iproc.push_back(second_node_pt);
11844  halo_edges_counter_jproc++;
11845 
11846  halo_edges_iproc.push_back(second_node_pt);
11847  halo_edges_iproc.push_back(third_node_pt);
11848  halo_edges_counter_jproc++;
11849 
11850  halo_edges_iproc.push_back(third_node_pt);
11851  halo_edges_iproc.push_back(first_node_pt);
11852  halo_edges_counter_jproc++;
11853 
11854  // Store the info. of the element used to create these edges
11855  std::pair<Node*, Node*> edge1 =
11856  std::make_pair(first_node_pt, second_node_pt);
11857  edgesi_to_element_pt[edge1] = el_pt;
11858 
11859  std::pair<Node*, Node*> edge2 =
11860  std::make_pair(second_node_pt, third_node_pt);
11861  edgesi_to_element_pt[edge2] = el_pt;
11862 
11863  std::pair<Node*, Node*> edge3 =
11864  std::make_pair(third_node_pt, first_node_pt);
11865  edgesi_to_element_pt[edge3] = el_pt;
11866 
11867  // Store the face index of the edge in the element
11868  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele1 =
11869  std::make_pair(edge1, el_pt);
11870  edgesi_element_pt_to_face_index[edge_ele1] = 2;
11871 
11872  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele2 =
11873  std::make_pair(edge2, el_pt);
11874  edgesi_element_pt_to_face_index[edge_ele2] = 0;
11875 
11876  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele3 =
11877  std::make_pair(edge3, el_pt);
11878  edgesi_element_pt_to_face_index[edge_ele3] = 1;
11879 
11880  } // for (ih < nhalo_elements_iproc_with_jproc)
11881 
11882  // **************************************************************
11883  // 1.2) Store the edges of the "jproc" halo elements
11884  // **************************************************************
11885  // Go throught halo elements on "jproc" processor
11886  for (unsigned jh = 0; jh < nhalo_elements_jproc_with_iproc; jh++)
11887  {
11888 #ifdef PARANOID
11889  unsigned e =
11890  element_to_global_index[halo_elements_jproc_with_iproc[jh]];
11891  // Only work with halo elements inside the "jproc" processor
11892  if (element_domain[e] != iproc)
11893  {
11894  // There was a problem on the jhalo-ihalo classification
11895  std::stringstream err;
11896  err << "There was a problem on the jhalo-ihalo classification.\n"
11897  << "One of the elements, (the one with the ("<<e<<")-th "
11898  << "index ) is not on the ("<<iproc<<")-th processor\n"
11899  << "but it was stored as a halo element of processor ("
11900  << jproc<<") with processor ("<<iproc<<").\n";
11901  throw OomphLibError(
11902  err.str(),
11903  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11904  OOMPH_EXCEPTION_LOCATION);
11905  }
11906 #endif
11907 
11908  FiniteElement* el_pt =
11909  dynamic_cast<FiniteElement*>(halo_elements_jproc_with_iproc[jh]);
11910  if (el_pt==0)
11911  {
11912  std::stringstream err;
11913  err << "The halo element ("<<jh<<") could not be casted to the "
11914  << "FiniteElement type.\n";
11915  throw OomphLibError(
11916  err.str(),
11917  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11918  OOMPH_EXCEPTION_LOCATION);
11919  }
11920 
11921 #ifdef PARANOID
11922  // Number of nodes on this element
11923  const unsigned n_nodes = el_pt->nnode();
11924 
11925  // The number of nodes on every element should be at least
11926  // three since we are going to work with the cornes nodes,
11927  // the ones with index 0, 1 and 2
11928  if (n_nodes<3)
11929  {
11930  std::stringstream err;
11931  err << "The number of nodes of the "<<jh<<"-th halo element is"
11932  << " ("<< n_nodes << ").\nWe can not work with triangle "
11933  << "elements with less than three nodes\n";
11934  throw OomphLibError(err.str(),
11935  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11936  OOMPH_EXCEPTION_LOCATION);
11937  }
11938 #endif
11939 
11940  // Get the nodes pointers
11941  Node *first_node_pt = el_pt->node_pt(0);
11942  Node *second_node_pt = el_pt->node_pt(1);
11943  Node *third_node_pt = el_pt->node_pt(2);
11944 
11945  // Store the edges
11946  halo_edges_jproc.push_back(first_node_pt);
11947  halo_edges_jproc.push_back(second_node_pt);
11948  halo_edges_counter_iproc++;
11949 
11950  halo_edges_jproc.push_back(second_node_pt);
11951  halo_edges_jproc.push_back(third_node_pt);
11952  halo_edges_counter_iproc++;
11953 
11954  halo_edges_jproc.push_back(third_node_pt);
11955  halo_edges_jproc.push_back(first_node_pt);
11956  halo_edges_counter_iproc++;
11957 
11958  // Store the info. of the element used to create these edges
11959  std::pair<Node*, Node*> edge1 =
11960  std::make_pair(first_node_pt, second_node_pt);
11961  edgesj_to_element_pt[edge1] = el_pt;
11962 
11963  std::pair<Node*, Node*> edge2 =
11964  std::make_pair(second_node_pt, third_node_pt);
11965  edgesj_to_element_pt[edge2] = el_pt;
11966 
11967  std::pair<Node*, Node*> edge3 =
11968  std::make_pair(third_node_pt, first_node_pt);
11969  edgesj_to_element_pt[edge3] = el_pt;
11970 
11971  // Store the face index of the edge in the element
11972  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele1 =
11973  std::make_pair(edge1, el_pt);
11974  edgesj_element_pt_to_face_index[edge_ele1] = 2;
11975 
11976  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele2 =
11977  std::make_pair(edge2, el_pt);
11978  edgesj_element_pt_to_face_index[edge_ele2] = 0;
11979 
11980  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele3 =
11981  std::make_pair(edge3, el_pt);
11982  edgesj_element_pt_to_face_index[edge_ele3] = 1;
11983 
11984  } // for (jh < nhalo_elements_jproc_with_iproc)
11985 
11986  // ***************************************************************
11987  // SECOND PART
11988  // 1) We already have the information of the edges on the iproc
11989  // halo and jproc halo elements
11990  // 2) Identify the shared edges to create the shared boundaries
11991  // (Only store the information but do not create the polyline)
11992  // ***************************************************************
11993 
11994  // Get the number of edges from each processor
11995  unsigned nhalo_iedges = halo_edges_iproc.size();
11996  unsigned nhalo_jedges = halo_edges_jproc.size();
11997 
11998  // Start comparing the edges to check which of those are
11999  // shared between the "ihalo_edge" and the "jhalo_edge"
12000  for (unsigned ihe = 0; ihe < nhalo_iedges; ihe+=2)
12001  {
12002  // Get the ihe-th edge (pair of nodes)
12003  Vector<Node*> ihalo_edge(2);
12004  ihalo_edge[0] = halo_edges_iproc[ihe];
12005  ihalo_edge[1] = halo_edges_iproc[ihe+1];
12006 
12007  // Create the pair that defines the edge
12008  std::pair<Node*,Node*> tmp_edge = std::make_pair(ihalo_edge[0],
12009  ihalo_edge[1]);
12010 
12011  // Check if the edge lies on a boundary (default values is
12012  // -1 for no association with an internal boundary)
12013  int edge_boundary_id = -1;
12014  {
12015  std::map<std::pair<Node*,Node*>,unsigned >::iterator it;
12016  it = elements_edges_on_boundary.find(tmp_edge);
12017  // If the edges lie on a boundary then get the boundary id
12018  // on which the edges lie
12019  if (it != elements_edges_on_boundary.end())
12020  {
12021  // Assign the internal boundary id associated with the
12022  // edge
12023  edge_boundary_id = (*it).second;
12024  }
12025  else
12026  {
12027  // Look for the reversed version of the edge (the nodes
12028  // inverted)
12029  std::pair<Node*,Node*> rtmp_edge = std::make_pair(ihalo_edge[1],
12030  ihalo_edge[0]);
12031  it = elements_edges_on_boundary.find(rtmp_edge);
12032  if (it != elements_edges_on_boundary.end())
12033  {
12034  // Assign the internal boundary id associated with the
12035  // edge
12036  edge_boundary_id = (*it).second;
12037  }
12038  }
12039  }
12040 
12041  // Go through the jhalo_edge and compare with the
12042  // ihalo_edge
12043  for (unsigned jhe = 0; jhe < nhalo_jedges; jhe+=2)
12044  {
12045  // Get the jhe-th edge (pair of nodes)
12046  Vector<Node*> jhalo_edge(2);
12047  jhalo_edge[0] = halo_edges_jproc[jhe];
12048  jhalo_edge[1] = halo_edges_jproc[jhe+1];
12049 
12050  // Comparing pointer of nodes
12051  if (ihalo_edge[0] == jhalo_edge[0] &&
12052  ihalo_edge[1] == jhalo_edge[1])
12053  {
12054  // Create the edge (both nodes that make the edge)
12055  std::pair<Node*, Node*> new_edge =
12056  std::make_pair(ihalo_edge[0], ihalo_edge[1]);
12057 
12058  // Get the elements involved in the creation of the
12059  // edge to check that there are elements associated to
12060  // the edge
12061  FiniteElement* haloi_ele_pt = 0;
12062  haloi_ele_pt = edgesi_to_element_pt[new_edge];
12063  FiniteElement* haloj_ele_pt = 0;
12064  haloj_ele_pt = edgesj_to_element_pt[new_edge];
12065 
12066  // Verify that there is an element associated with it
12067  if (haloi_ele_pt == 0 || haloj_ele_pt == 0)
12068  {
12069  std::stringstream err;
12070  err << "There is no associated elements with the new "
12071  << "shared boundary. This is an storing problem,\n"
12072  << "possibly related with a memory leak problem!!!\n"
12073  << "The nodes that compound the edge are these:\n"
12074  << "On processor ("<<iproc<<"):\n"
12075  << "("<<ihalo_edge[0]->x(0)<<", "<<ihalo_edge[0]->x(1)
12076  <<") and ("<<ihalo_edge[1]->x(0)<<", "
12077  <<ihalo_edge[1]->x(1)<<")\n\n"
12078  << "On processor ("<<jproc<<"):\n"
12079  << "("<<jhalo_edge[0]->x(0)<<", "<<jhalo_edge[0]->x(1)
12080  <<") and ("<<jhalo_edge[1]->x(0)<<", "
12081  <<jhalo_edge[1]->x(1)<<")\n\n"
12082  << "The nodes coordinates should be the same!!!\n";
12083  throw OomphLibError(err.str(),
12084  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12085  OOMPH_EXCEPTION_LOCATION);
12086  }
12087 
12088  // Store the edge
12089  edges[iproc][jproc].push_back(new_edge);
12090 
12091  // Is the edge overlapped by a shared boundary
12092  if (edge_boundary_id >= 0)
12093  {
12094  // Mark the edge as overlapped
12095  overlapped_edge[new_edge] = true;
12096 
12097  // Also mark the reversed edge
12098  std::pair<Node*, Node*> rev_new_edge =
12099  std::make_pair(ihalo_edge[1], ihalo_edge[0]);
12100 
12101  // Mark the edge as overlapped
12102  overlapped_edge[rev_new_edge] = true;
12103 
12104  } // if (edge_boundary_id >= 0)
12105 
12106  // Store the internal boundary id (default -1)
12107  // associated to the edge
12108  edge_boundary[iproc][jproc].push_back(edge_boundary_id);
12109 
12110  // Store the two elements associated with the edge
12111  Vector<FiniteElement*> tmp_elements_pt;
12112  tmp_elements_pt.push_back(haloi_ele_pt);
12113  tmp_elements_pt.push_back(haloj_ele_pt);
12114 
12115  // Associate the edge with the elements that gave rise to it
12116  edge_element_pt[iproc][jproc].push_back(tmp_elements_pt);
12117 
12118  // Get the face index on each element that gave rise to
12119  // the edge
12120 
12121  // .. first create the pair (edge, finite_element)
12122  std::pair<std::pair<Node*,Node*>, FiniteElement*>
12123  edge_elementi_pair = make_pair(new_edge, haloi_ele_pt);
12124 
12125  std::pair<std::pair<Node*,Node*>, FiniteElement*>
12126  edge_elementj_pair = make_pair(new_edge, haloj_ele_pt);
12127 
12128  // Set default values to later check if values were
12129  // read from the map structure
12130  int face_index_haloi_ele = -1;
12131  face_index_haloi_ele =
12132  edgesi_element_pt_to_face_index[edge_elementi_pair];
12133  int face_index_haloj_ele = -1;
12134  face_index_haloj_ele =
12135  edgesj_element_pt_to_face_index[edge_elementj_pair];
12136  // Verify that there is an element associated with it
12137  if (face_index_haloi_ele == -1 || face_index_haloj_ele == -1)
12138  {
12139  std::stringstream err;
12140  err << "There is no associated face indexes to the"
12141  << "elements that gave\nrise to the shared edge\n"
12142  << "The nodes that compound the edge are these:\n"
12143  << "On processor ("<<iproc<<"):\n"
12144  << "("<<ihalo_edge[0]->x(0)<<", "<<ihalo_edge[0]->x(1)
12145  <<") and ("<<ihalo_edge[1]->x(0)<<", "
12146  <<ihalo_edge[1]->x(1)<<")\n\n"
12147  << "On processor ("<<jproc<<"):\n"
12148  << "("<<jhalo_edge[0]->x(0)<<", "<<jhalo_edge[0]->x(1)
12149  <<") and ("<<jhalo_edge[1]->x(0)<<", "
12150  <<jhalo_edge[1]->x(1)<<")\n\n"
12151  << "The nodes coordinates should be the same!!!\n";
12152  throw OomphLibError(err.str(),
12153  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12154  OOMPH_EXCEPTION_LOCATION);
12155  } // if (face_index_haloi_ele == -1 ||
12156  // face_index_haloj_ele == -1)
12157 
12158  // Get the face indexes from the map structure
12159  Vector<int> tmp_edge_element_face_index;
12160  tmp_edge_element_face_index.push_back(face_index_haloi_ele);
12161  tmp_edge_element_face_index.push_back(face_index_haloj_ele);
12162  // Store the face indexes
12163  edge_element_face[iproc][jproc].
12164  push_back(tmp_edge_element_face_index);
12165 
12166  break; // break for (jhe < nhalo_jedges) since edge
12167  // found
12168 
12169  } // if (ihalo_edge[0] == jhalo_edge[0] &&
12170  // ihalo_edge[1] == jhalo_edge[1])
12171  // Comparing nodes pointers
12172  else if (ihalo_edge[0] == jhalo_edge[1] &&
12173  ihalo_edge[1] == jhalo_edge[0])
12174  {
12175  // Create the edge (both nodes that make the edge)
12176  std::pair<Node*, Node*> new_edge =
12177  std::make_pair(ihalo_edge[0], ihalo_edge[1]);
12178 
12179  // Get the elements involved in the creation of the
12180  // edge
12181  FiniteElement* haloi_ele_pt = 0;
12182  haloi_ele_pt = edgesi_to_element_pt[new_edge];
12183 
12184  FiniteElement* haloj_ele_pt = 0;
12185  // Create the edge (reversed, that is how it was
12186  // originally stored)
12187  std::pair<Node*, Node*> new_edge_reversed =
12188  std::make_pair(jhalo_edge[0], jhalo_edge[1]);
12189  haloj_ele_pt = edgesj_to_element_pt[new_edge_reversed];
12190 
12191  // Verify that there is an element associated with it
12192  if (haloi_ele_pt == 0 || haloj_ele_pt == 0)
12193  {
12194  std::stringstream err;
12195  err << "There is no associated elements with the new "
12196  << "shared boundary (reversed version). This is an "
12197  << "storing problem, possibly related with a memory "
12198  << "leak problem!!!\n"
12199  << "The nodes that compound the edge are these:\n"
12200  << "On processor ("<<iproc<<"):\n"
12201  << "("<<ihalo_edge[0]->x(0)<<", "<<ihalo_edge[0]->x(1)
12202  <<") and ("<<ihalo_edge[1]->x(0)<<", "
12203  <<ihalo_edge[1]->x(1)<<")\n\n"
12204  << "On processor ("<<jproc<<"):\n"
12205  << "("<<jhalo_edge[0]->x(0)<<", "<<jhalo_edge[0]->x(1)
12206  <<") and ("<<jhalo_edge[1]->x(0)<<", "
12207  <<jhalo_edge[1]->x(1)<<")\n\n"
12208  << "The nodes coordinates should be the same!!!\n";
12209  throw OomphLibError(err.str(),
12210  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12211  OOMPH_EXCEPTION_LOCATION);
12212  }
12213 
12214  // Store the edge
12215  edges[iproc][jproc].push_back(new_edge);
12216 
12217  // Is the edge overlapped by a shared boundary
12218  if (edge_boundary_id >= 0)
12219  {
12220  // Mark the edge as overlapped
12221  overlapped_edge[new_edge] = true;
12222 
12223  // Also mark the reversed edge
12224  std::pair<Node*, Node*> rev_new_edge =
12225  std::make_pair(ihalo_edge[1], ihalo_edge[0]);
12226 
12227  // Mark the edge as overlapped
12228  overlapped_edge[rev_new_edge] = true;
12229  } // if (edge_boundary_id >= 0)
12230 
12231  // Store the internal boundary id (default -1)
12232  // associated to the edge
12233  edge_boundary[iproc][jproc].push_back(edge_boundary_id);
12234 
12235  // Store the two elements associated with the edge
12236  Vector<FiniteElement*> tmp_elements_pt;
12237  tmp_elements_pt.push_back(haloi_ele_pt);
12238  tmp_elements_pt.push_back(haloj_ele_pt);
12239 
12240  // Associate the edge with the elements that gave rise to it
12241  edge_element_pt[iproc][jproc].push_back(tmp_elements_pt);
12242 
12243  // Get the face index on each element that gave rise to
12244  // the edge
12245 
12246  // .. first create the pair (edge, finite_element)
12247  std::pair<std::pair<Node*,Node*>, FiniteElement*>
12248  edge_elementi_pair = make_pair(new_edge, haloi_ele_pt);
12249 
12250  std::pair<std::pair<Node*,Node*>, FiniteElement*>
12251  edge_elementj_pair = make_pair(new_edge_reversed,
12252  haloj_ele_pt);
12253 
12254  // Set default values to later check if values were
12255  // read from the map structure
12256  int face_index_haloi_ele = -1;
12257  face_index_haloi_ele =
12258  edgesi_element_pt_to_face_index[edge_elementi_pair];
12259  int face_index_haloj_ele = -1;
12260  face_index_haloj_ele =
12261  edgesj_element_pt_to_face_index[edge_elementj_pair];
12262  // Verify that there is an element associated with it
12263  if (face_index_haloi_ele == -1 || face_index_haloj_ele == -1)
12264  {
12265  std::stringstream err;
12266  err << "There is no associated face indexes to the"
12267  << "elements that gave\nrise to the shared edge\n"
12268  << "The nodes that compound the edge are these:\n"
12269  << "On processor ("<<iproc<<"):\n"
12270  << "("<<ihalo_edge[0]->x(0)<<", "<<ihalo_edge[0]->x(1)
12271  <<") and ("<<ihalo_edge[1]->x(0)<<", "
12272  <<ihalo_edge[1]->x(1)<<")\n\n"
12273  << "On processor ("<<jproc<<"):\n"
12274  << "("<<jhalo_edge[0]->x(0)<<", "<<jhalo_edge[0]->x(1)
12275  <<") and ("<<jhalo_edge[1]->x(0)<<", "
12276  <<jhalo_edge[1]->x(1)<<")\n\n"
12277  << "The nodes coordinates should be the same!!!\n";
12278  throw OomphLibError(err.str(),
12279  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12280  OOMPH_EXCEPTION_LOCATION);
12281  } // if (face_index_haloi_ele == -1 ||
12282  // face_index_haloj_ele == -1)
12283 
12284  // Get the face indexes from the map structure
12285  Vector<int> tmp_edge_element_face_index;
12286  tmp_edge_element_face_index.push_back(face_index_haloi_ele);
12287  tmp_edge_element_face_index.push_back(face_index_haloj_ele);
12288  // Store the face indexes
12289  edge_element_face[iproc][jproc].
12290  push_back(tmp_edge_element_face_index);
12291 
12292  break; // break for (jhe < nhalo_jedges) since edge found
12293 
12294  } // else if (ihalo_edge[0] == jhalo_edge[1] &&
12295  // ihalo_edge[1] == jhalo_edge[0])
12296 
12297  } // for (jhe < nhaloj_edges)
12298 
12299  } // for (ihe < nhaloi_edges)
12300 
12301  } // if (nhalo_elements_iproc_with_jproc > 0)
12302 
12303  } // for (jproc < nproc)
12304 
12305  } // for (iproc < nproc)
12306 
12307  // ------------------------------------------------------------------
12308  // Compute the degree of each node in the shared edges
12309  // ------------------------------------------------------------------
12310 
12311  // Visit all the shared edges between each pair of processors,
12312  // visit the nodes of each edge and compute the degree of each node
12313 
12314  // Store the degree (valency) of each node
12315  std::map<Node*, unsigned> global_shared_node_degree;
12316 
12317 #ifdef PARANOID
12318  // Map to check if an edge has been already visited
12319  std::map<std::pair<Node*, Node*>,bool> edge_done;
12320 #endif // #ifdef PARANOID
12321  // Map to check if a node has been already visited
12322  std::map<Node*,bool> node_done;
12323 
12324  // Loop over the processors and get the shared edged between each
12325  // pair of processors
12326  for (unsigned iproc = 0; iproc < nproc; iproc++)
12327  {
12328  // Start from iproc + 1 to avoid checking with itself (there is
12329  // no shared edges between the same processor), and to avoid
12330  // double counting the edges and nodes (the shared edges between
12331  // processor (iproc, jproc) are the same as those between
12332  // processor jproc, iproc)
12333  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
12334  {
12335  // Get the number of edges shared between the pair of processors
12336  const unsigned nshd_edges = edges[iproc][jproc].size();
12337 #ifdef PARANOID
12338  // There must be the same number of information on each of the
12339  // containers
12340 
12341  // Get the number of edge elements
12342  const unsigned nedge_element = edge_element_pt[iproc][jproc].size();
12343  if (nshd_edges != nedge_element)
12344  {
12345  std::stringstream error_message;
12346  error_message
12347  << "The number of shared edges between processor iproc and jproc\n"
12348  << "is different form the number of edge elements between the\n"
12349  << "pair of processors\n"
12350  << "iproc: (" << iproc << ")\n"
12351  << "jproc: (" << jproc << ")\n"
12352  << "# of shared edges: (" << nshd_edges << ")\n"
12353  << "# of edge elements: (" << nedge_element << ")\n\n";
12354  throw OomphLibError(error_message.str(),
12355  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12356  OOMPH_EXCEPTION_LOCATION);
12357  }
12358 
12359  // Get the number of edge element faces
12360  const unsigned nedge_element_face =
12361  edge_element_face[iproc][jproc].size();
12362  if (nshd_edges != nedge_element_face)
12363  {
12364  std::stringstream error_message;
12365  error_message
12366  << "The number of shared edges between processor iproc and jproc\n"
12367  << "is different form the number of edge element faces between the\n"
12368  << "pair of processors\n"
12369  << "iproc: (" << iproc << ")\n"
12370  << "jproc: (" << jproc << ")\n"
12371  << "# of shared edges: (" << nshd_edges << ")\n"
12372  << "# of edge element faces: (" << nedge_element_face << ")\n\n";
12373  throw OomphLibError(error_message.str(),
12374  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12375  OOMPH_EXCEPTION_LOCATION);
12376  }
12377 
12378  // Get the number of edge boundaries
12379  const unsigned nedge_boundary = edge_boundary[iproc][jproc].size();
12380  if (nshd_edges != nedge_boundary)
12381  {
12382  std::stringstream error_message;
12383  error_message
12384  << "The number of shared edges between processor iproc and jproc\n"
12385  << "is different form the number of edge boundaries ids between the\n"
12386  << "pair of processors\n"
12387  << "iproc: (" << iproc << ")\n"
12388  << "jproc: (" << jproc << ")\n"
12389  << "# of shared edges: (" << nshd_edges << ")\n"
12390  << "# of edge boundaries ids: (" << nedge_boundary << ")\n\n";
12391  throw OomphLibError(error_message.str(),
12392  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12393  OOMPH_EXCEPTION_LOCATION);
12394  }
12395 
12396 #endif // #ifdef PARANOID
12397 
12398  // Loop over the shared edges between (iproc, jproc) processors
12399  for (unsigned se = 0; se < nshd_edges; se++)
12400  {
12401  // Get the edge
12402  std::pair<Node*, Node*> edge = edges[iproc][jproc][se];
12403 #ifdef PARANOID
12404  // Check that the edge has not been previously visited
12405  if (edge_done[edge])
12406  {
12407  std::stringstream error_message;
12408  error_message
12409  << "The shared edge between processor iproc and processor\n"
12410  << "jproc has been already visited, this is weird since the\n"
12411  << "edge should not be shared by other pair of processors\n"
12412  << "iproc: (" << iproc << ")\n"
12413  << "jproc: (" << jproc << ")\n"
12414  << "First node of edge: (" << edge.first->x(0) << ", "
12415  << edge.first->x(1) << ")\n"
12416  << "Second node of edge: (" << edge.second->x(0) << ", "
12417  << edge.second->x(1) << ")\n"
12418  << "Associated edge boundary id: ("
12419  << edge_boundary[iproc][jproc][se] << ")\n\n";
12420  throw OomphLibError(error_message.str(),
12421  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12422  OOMPH_EXCEPTION_LOCATION);
12423  }
12424 
12425  // Mark the edge as done
12426  edge_done[edge] = true;
12427  // Create the reversed version and include it too
12428  std::pair<Node*, Node*> rev_edge =
12429  std::make_pair(edge.second, edge.first);
12430  // Mark reversed edge as done
12431  edge_done[rev_edge] = true;
12432 #endif // #ifdef PARANOID
12433 
12434  // Get each of the nodes that conform the edge
12435  Node* left_node_pt = edge.first;
12436  Node* right_node_pt = edge.second;
12437 
12438  // Check if the left node has been already done
12439  if (!node_done[left_node_pt])
12440  {
12441  // Set the degree of the node to once since this is the
12442  // first time it has been found
12443  global_shared_node_degree[left_node_pt] = 1;
12444 
12445  } // if (!done_node[left_node_pt])
12446  else
12447  {
12448  // Increase the degree of the node
12449  global_shared_node_degree[left_node_pt]++;
12450  }
12451 
12452  // Check if the right node has been already done
12453  if (!node_done[right_node_pt])
12454  {
12455  // Set the degree of the node to once since this is the
12456  // first time it has been found
12457  global_shared_node_degree[right_node_pt] = 1;
12458  } // if (!done_node[right_node_pt])
12459  else
12460  {
12461  // Increase the degree of the node
12462  global_shared_node_degree[right_node_pt]++;
12463  }
12464 
12465  } // for (se < nshd_edges)
12466 
12467  } // for (jproc < nproc)
12468 
12469  } // for (iproc < nproc)
12470 
12471  // -----------------------------------------------------------------
12472  // Identify those nodes living on edges of original boundaries not
12473  // overlapped by a shared boundary
12474 
12475  // Mark the nodes on original boundaries not overlapped by shared
12476  // boundaries
12477  std::map<unsigned, std::map<Node*, bool> >
12478  node_on_bnd_not_overlapped_by_shd_bnd;
12479 
12480  // Loop over the edges of the original boundaries
12481  for (std::map<std::pair<Node*,Node*>, unsigned>::iterator it_map =
12482  elements_edges_on_boundary.begin();
12483  it_map != elements_edges_on_boundary.end(); it_map++)
12484  {
12485  // Get the edge
12486  std::pair<Node*,Node*> edge_pair = (*it_map).first;
12487 
12488  // Is the edge overlaped by a shared boundary
12489  if (!overlapped_edge[edge_pair])
12490  {
12491  // Mark the nodes of the edge as being on an edge not overlaped
12492  // by a shared boundary on the boundary the edge is
12493  unsigned b = (*it_map).second;
12494 
12495  // Get the left node
12496  Node* left_node_pt = edge_pair.first;
12497  node_on_bnd_not_overlapped_by_shd_bnd[b][left_node_pt] = true;
12498 
12499  // Get the right node
12500  Node* right_node_pt = edge_pair.second;
12501  node_on_bnd_not_overlapped_by_shd_bnd[b][right_node_pt] = true;
12502 
12503  } // if (!overlapped_edge[edge_pair])
12504 
12505  } // Loop over edges to mark those nodes on overlaped edge by
12506  // shared boundaries
12507 
12508  // ------------------------------------------------------------------
12509  // Now create the shared polylines but including the degree of the
12510  // nodes as a nw stop condition for adding more edges to the side
12511  // or a root edge
12512  // ------------------------------------------------------------------
12513 
12514  // Storage for new created polylines with "each processor", non
12515  // sorted (shared polylines of the current processor only)
12516  Vector<Vector<TriangleMeshPolyLine *> > unsorted_polylines_pt(nproc);
12517 
12518  // Map that associates the shared boundary id with the list of
12519  // nodes that create it (shared boundary of the current processor
12520  // only)
12521  std::map<unsigned, std::list<Node*> > shared_bnd_id_to_sorted_list_node_pt;
12522 
12523  // Get maximum user boundary id and set the initial shared boundary
12524  // id
12525  unsigned shared_boundary_id_start = this->nboundary();
12526  Initial_shared_boundary_id = shared_boundary_id_start;
12527 
12528  // Aqui
12529 
12530  // Loop over the processors and get the shared edged between each
12531  // pair of processors
12532  for (unsigned iproc = 0; iproc < nproc; iproc++)
12533  {
12534  // Start from iproc + 1 to avoid checking with itself (there is
12535  // no shared edges between the same processor), and to avoid
12536  // double counting the edges and nodes (the shared edges between
12537  // processor (iproc, jproc) are the same as those between
12538  // processor jproc, iproc)
12539  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
12540  {
12541  // *************************************************************
12542  // THIRD PART
12543  // 1) Sort the edges (make them contiguous) so that they can
12544  // be used as the vertex coordinates that define a shared
12545  // boundary (polyline)
12546  // *************************************************************
12547  unsigned npolylines_counter = 0;
12548  const unsigned nedges = edges[iproc][jproc].size();
12549 
12550  // -----------------------------------------------------------
12551  // Compute all the SHARED POLYLINES
12552  // -----------------------------------------------------------
12553  // The number of sorted edges
12554  unsigned nsorted_edges = 0;
12555 
12556  // Keep track of the already done edges
12557  std::map<std::pair<Node*,Node*>, bool> edge_done;
12558 
12559  // Loop over all the edges to create all the polylines with
12560  // the current processors involved
12561  while(nsorted_edges < nedges)
12562  {
12563  // Temporaly storage for the elements associated to the
12564  // sorted edges
12565  std::list<FiniteElement*> tmp_boundary_element_pt;
12566  // Temporly storage for the face indexes on the element
12567  // that created the given edge
12568  std::list<int> tmp_face_index_element;
12569  // Get an initial pair of nodes to create an edge
12570  std::pair<Node*,Node*> edge;
12571 #ifdef PARANOID
12572  bool found_initial_edge = false;
12573 #endif
12574  int root_edge_bound_id = -1;
12575  unsigned iedge = 0;
12576  for (iedge = 0; iedge < nedges; iedge++)
12577  {
12578  edge = edges[iproc][jproc][iedge];
12579  // If not done then take it as initial edge
12580  if (!edge_done[edge])
12581  {
12582  // Get the boundary id that the edge may be overlapping
12583  root_edge_bound_id = edge_boundary[iproc][jproc][iedge];
12584 #ifdef PARANOID
12585  found_initial_edge = true;
12586 #endif
12587  nsorted_edges++;
12588  iedge++;
12589  break;
12590  } // if (!edge_done[edge])
12591  } // for (iedge < nedges)
12592 
12593 #ifdef PARANOID
12594  if (!found_initial_edge)
12595  {
12596  std::ostringstream error_message;
12597  error_message
12598  << "All the edge are already done, but the number of done\n"
12599  << "edges ("<<nsorted_edges<<") is still less than the total\n"
12600  << "number of edges (" << nedges << ").\n";
12601  // << "----- Possible memory leak -----\n";
12602  throw OomphLibError(error_message.str(),
12603  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12604  OOMPH_EXCEPTION_LOCATION);
12605  }
12606 #endif
12607 
12608  // Storing for the sorting nodes extracted from the
12609  // edges. The sorted nodes are used to create a polyline
12610  std::list<Node*> sorted_nodes;
12611  sorted_nodes.clear();
12612 
12613  // The initial and final nodes of the list
12614  Node *first_node_pt = edge.first;
12615  Node *last_node_pt = edge.second;
12616 
12617  // Push back on the list the new edge (nodes)
12618  sorted_nodes.push_back(first_node_pt);
12619  sorted_nodes.push_back(last_node_pt);
12620 
12621  // Get the elements associated to the edge and store them
12622  // in the temporaly boundary elements storage
12623  tmp_boundary_element_pt.
12624  push_back(edge_element_pt[iproc][jproc][iedge-1][0]);
12625  tmp_boundary_element_pt.
12626  push_back(edge_element_pt[iproc][jproc][iedge-1][1]);
12627 
12628  // ... then get the face index of the element from where
12629  // the edge came from
12630  tmp_face_index_element.
12631  push_back(edge_element_face[iproc][jproc][iedge-1][0]);
12632  tmp_face_index_element.
12633  push_back(edge_element_face[iproc][jproc][iedge-1][1]);
12634 
12635  // Mark edge as done
12636  edge_done[edge] = true;
12637 
12638  // Continue iterating if a new node (that creates a new
12639  // edge) is added to the list, we have just added two nodes
12640  // (the first and last of the root edge)
12641  bool node_added = true;
12642 
12643  // Flags to indicate at which end the node was added (left
12644  // or right)
12645  bool node_added_to_the_left = true;
12646  bool node_added_to_the_right = true;
12647 
12648  // The nodes that create a shared boundary are obtained by
12649  // connecting the edges shared by the halo and haloed
12650  // elements. These edges are connected to left or right of
12651  // the shared boundary. Every time a new edge is added to
12652  // the left (or right), the most left (or right) node is
12653  // searched in the list of nodes of previous shared
12654  // boundaries, if the node is found then it is said to be
12655  // shared with another boundary and a connection to that
12656  // boundary needs to be specified. We stop adding edges
12657  // (and nodes) to the side where that nodes was found to be
12658  // shared. Note that the intersection (shared node) may be
12659  // with the same shared boundary
12660 
12661  // Flag to indicate a node was found to be shared with
12662  // another boundary at the left end (most left node) of the
12663  // shared boundary
12664  bool connection_to_the_left = false;
12665 
12666  // Flag to indicate a node was found to be shared with
12667  // another boundary at the right end (most right node) of
12668  // the shared boundary
12669  bool connection_to_the_right = false;
12670 
12671  // Flag to stop the adding of edges (and nodes) to the
12672  // current shared boundary
12673  bool current_polyline_has_connections_at_both_ends = false;
12674 
12675  // Store the boundary ids of the polylines to connect (only
12676  // used when the polyline was found to have a connection)
12677  // -1: Indicates no connection
12678  // -2: Indicates connection with itself
12679  // Any other value: Boundary id to connect
12680  int bound_id_connection_to_the_left = -1;
12681  int bound_id_connection_to_the_right = -1;
12682 
12683  // Get the degree of the first node
12684  const unsigned first_node_degree =
12685  global_shared_node_degree[first_node_pt];
12686 
12687  // Check if the nodes of the root edge have connections
12688  // ... to the left
12689  bound_id_connection_to_the_left =
12690  check_connections_of_polyline_nodes(
12691  element_in_processor_pt,
12692  root_edge_bound_id,
12693  overlapped_edge,
12694  node_on_bnd_not_overlapped_by_shd_bnd,
12695  sorted_nodes,
12696  shared_bnd_id_to_sorted_list_node_pt,
12697  first_node_degree,
12698  first_node_pt);
12699 
12700  // If there is a connection then set the
12701  // corresponding flag
12702  // (-1): No connection
12703  // (-2): Connection with itself
12704  // (-3): No connection, stop adding nodes
12705  // (other value): Boundary id
12706  if (bound_id_connection_to_the_left != -1)
12707  {
12708  connection_to_the_left = true;
12709  } // if (bound_id_connection_to_the_left != -1)
12710 
12711  // Get the degree of the last node
12712  const unsigned last_node_degree =
12713  global_shared_node_degree[last_node_pt];
12714 
12715  // Check if the nodes of the root edge have connections
12716  // ... to the right
12717  bound_id_connection_to_the_right =
12718  check_connections_of_polyline_nodes(
12719  element_in_processor_pt,
12720  root_edge_bound_id,
12721  overlapped_edge,
12722  node_on_bnd_not_overlapped_by_shd_bnd,
12723  sorted_nodes,
12724  shared_bnd_id_to_sorted_list_node_pt,
12725  last_node_degree,
12726  last_node_pt);
12727 
12728  // If there is a connection then set the
12729  // corresponding flag
12730  // (-1): No connection
12731  // (-2): Connection with itself
12732  // (other value): Boundary id
12733  if (bound_id_connection_to_the_right != -1)
12734  {
12735  connection_to_the_right = true;
12736  } // if (bound_id_connection_to_the_right != -1)
12737 
12738  // If the current shared boundary has connections at both
12739  // ends then stop the adding of nodes
12740  if (connection_to_the_left && connection_to_the_right)
12741  {current_polyline_has_connections_at_both_ends = true;}
12742 
12743  // Continue searching for more edges if
12744  // 1) A new node was added at the left or right of the list
12745  // 2) There are more edges to possible add
12746  // 3) The added node is not part of any other previous
12747  // shared polyline
12748  while(node_added && (nsorted_edges < nedges)
12749  && !current_polyline_has_connections_at_both_ends)
12750  {
12751  // Start from the next edge since we have already added
12752  // the previous one as the initial edge (any previous
12753  // edge had to be added to previous polylines)
12754  for (unsigned iiedge = iedge; iiedge < nedges; iiedge++)
12755  {
12756  // Reset the flags for added nodes, to the left and right
12757  node_added = false;
12758  node_added_to_the_left = false;
12759  node_added_to_the_right = false;
12760  // Get the current edge
12761  edge = edges[iproc][jproc][iiedge];
12762  const int edge_bound_id = edge_boundary[iproc][jproc][iiedge];
12763 
12764  // We need to ensure to connect with edges that share
12765  // the same bound id or with those that has no boundary
12766  // id associated (the default -1 value), may apply
12767  // exclusively to internal boundaries
12768  if (!edge_done[edge] &&
12769  (edge_bound_id == root_edge_bound_id))
12770  {
12771  // Get each individual node
12772  Node* left_node_pt = edge.first;
12773  Node* right_node_pt = edge.second;
12774 
12775  // Pointer to the new added node
12776  Node* new_added_node_pt = 0;
12777 
12778  // Is the node to be added to the left?
12779  if (left_node_pt == first_node_pt &&
12780  !connection_to_the_left)
12781  {
12782  // Push front the new node
12783  sorted_nodes.push_front(right_node_pt);
12784  // Update the new added node and the first node
12785  new_added_node_pt = first_node_pt = right_node_pt;
12786  // Set the node added flag to true
12787  node_added = true;
12788  // Indicate the node was added to the left
12789  node_added_to_the_left = true;
12790  }
12791  // Is the node to be added to the right?
12792  else if (left_node_pt == last_node_pt &&
12793  !connection_to_the_right)
12794  {
12795  // Push back the new node
12796  sorted_nodes.push_back(right_node_pt);
12797  // Update the new added node and the last node
12798  new_added_node_pt = last_node_pt = right_node_pt;
12799  // Set the node added flag to true
12800  node_added = true;
12801  // Indicate the node was added to the right
12802  node_added_to_the_right = true;
12803  }
12804  // Is the node to be added to the left?
12805  else if (right_node_pt == first_node_pt &&
12806  !connection_to_the_left)
12807  {
12808  // Push front the new node
12809  sorted_nodes.push_front(left_node_pt);
12810  // Update the new added node and the first node
12811  new_added_node_pt = first_node_pt = left_node_pt;
12812  // Set the node added flag to true
12813  node_added = true;
12814  // Indicate the node was added to the left
12815  node_added_to_the_left = true;
12816  }
12817  // Is the node to be added to the right?
12818  else if (right_node_pt == last_node_pt &&
12819  !connection_to_the_right)
12820  {
12821  // Push back the new node
12822  sorted_nodes.push_back(left_node_pt);
12823  // Update the new added node and the last node
12824  new_added_node_pt = last_node_pt = left_node_pt;
12825  // Set the node added flag to true
12826  node_added = true;
12827  // Indicate the node was added to the right
12828  node_added_to_the_right = true;
12829  }
12830 
12831  // If we added a new node then we need to check if
12832  // that node has been already added in other shared
12833  // boundaries (which may define a connection)
12834  if (node_added)
12835  {
12836  // Mark as done only if one of its nodes has been
12837  // added to the list
12838  edge_done[edge] = true;
12839  nsorted_edges++;
12840 
12841  // Get the degree of the added node
12842  const unsigned added_node_degree =
12843  global_shared_node_degree[new_added_node_pt];
12844 
12845  if (node_added_to_the_left)
12846  {
12847  // Add the bulk elements
12848  tmp_boundary_element_pt.push_front(
12849  edge_element_pt[iproc][jproc][iiedge][1]);
12850  tmp_boundary_element_pt.push_front(
12851  edge_element_pt[iproc][jproc][iiedge][0]);
12852  // Add the face elements
12853  tmp_face_index_element.push_front(
12854  edge_element_face[iproc][jproc][iiedge][1]);
12855  tmp_face_index_element.push_front(
12856  edge_element_face[iproc][jproc][iiedge][0]);
12857  }
12858 
12859  if (node_added_to_the_right)
12860  {
12861  // Add the bulk elements
12862  tmp_boundary_element_pt.push_back(
12863  edge_element_pt[iproc][jproc][iiedge][0]);
12864  tmp_boundary_element_pt.push_back(
12865  edge_element_pt[iproc][jproc][iiedge][1]);
12866  // Add the face elements
12867  tmp_face_index_element.push_back(
12868  edge_element_face[iproc][jproc][iiedge][0]);
12869  tmp_face_index_element.push_back(
12870  edge_element_face[iproc][jproc][iiedge][1]);
12871  }
12872 
12873  // Based on which side the node was added, look for
12874  // connections on that side
12875 
12876  // Verify for connections to the left (we need to
12877  // check for the connection variable too, since
12878  // after a connection has been done we no longer
12879  // need to verify for this condition)
12880  if (node_added_to_the_left && !connection_to_the_left)
12881  {
12882  // Check for connection
12883  bound_id_connection_to_the_left =
12884  check_connections_of_polyline_nodes(
12885  element_in_processor_pt,
12886  root_edge_bound_id,
12887  overlapped_edge,
12888  node_on_bnd_not_overlapped_by_shd_bnd,
12889  sorted_nodes,
12890  shared_bnd_id_to_sorted_list_node_pt,
12891  added_node_degree,
12892  new_added_node_pt);
12893 
12894  // If there is a connection then set the
12895  // corresponding flag
12896  // (-1): No connection
12897  // (-2): Connection with itself
12898  // (other value): Boundary id
12899  if (bound_id_connection_to_the_left != -1)
12900  {
12901  connection_to_the_left = true;
12902  } // if (bound_id_connection_to_the_left != -1)
12903 
12904  } // if (node_added_to_the_left &&
12905  // !connection_to_the_left)
12906 
12907  // Verify for connections to the right (we need to
12908  // check for the connection variable too, since
12909  // after a connection has been done we no longer
12910  // need to verify for this condition)
12911  if (node_added_to_the_right && !connection_to_the_right)
12912  {
12913  // Check for connection
12914  bound_id_connection_to_the_right =
12915  check_connections_of_polyline_nodes(
12916  element_in_processor_pt,
12917  root_edge_bound_id,
12918  overlapped_edge,
12919  node_on_bnd_not_overlapped_by_shd_bnd,
12920  sorted_nodes,
12921  shared_bnd_id_to_sorted_list_node_pt,
12922  added_node_degree,
12923  new_added_node_pt);
12924 
12925  // If there is a connection then set the
12926  // corresponding flag
12927  // (-1): No connection
12928  // (-2): Connection with itself
12929  // (other value): Boundary id
12930  if (bound_id_connection_to_the_right != -1)
12931  {
12932  connection_to_the_right = true;
12933  } // if (bound_id_connection_to_the_right != -1)
12934 
12935  } // if (node_added_to_the_right &&
12936  // !connection_to_the_right)
12937 
12938  // If the current shared boundary has connections
12939  // at both ends then stop the adding of nodes
12940  if (connection_to_the_left && connection_to_the_right)
12941  {current_polyline_has_connections_at_both_ends = true;}
12942 
12943  // Break the for and re-start to look more edges to
12944  // the left or right
12945  break;
12946 
12947  } // if (node_added)
12948 
12949  } // if (!edge_done[edge])
12950  } // for (iiedge < nedges)
12951 
12952  } // while(node_added && (nsorted_edges < nedges)
12953  // && !current_polyline_has_connections_at_both_ends)
12954 
12955  // ------------------------------------------------------------
12956  // If the sorted nodes of the shared polyline create a loop
12957  // it is necessary to break it by creating as many
12958  // polylines as required
12959 
12960  // Change the list to a vector representation of the
12961  // boundary elements and the face indexes
12962 
12963  // Get the number of boundary elements
12964  const unsigned n_bnd_ele = tmp_boundary_element_pt.size();
12965 
12966  // Storage for the boundary elements and face indexes
12967  Vector<FiniteElement*> tmp_bnd_ele_pt(n_bnd_ele);
12968  Vector<int> tmp_face_idx_ele(n_bnd_ele);
12969  // Helper counter
12970  unsigned help_counter = 0;
12971  // Fill the data structures
12972  for (std::list<FiniteElement*>::iterator it_bnd_ele =
12973  tmp_boundary_element_pt.begin();
12974  it_bnd_ele != tmp_boundary_element_pt.end();
12975  it_bnd_ele++)
12976  {
12977  tmp_bnd_ele_pt[help_counter++] = (*it_bnd_ele);
12978  }
12979 
12980  // Restart counter
12981  help_counter = 0;
12982  for (std::list<int>::iterator it_face_idx =
12983  tmp_face_index_element.begin();
12984  it_face_idx != tmp_face_index_element.end();
12985  it_face_idx++)
12986  {
12987  tmp_face_idx_ele[help_counter++] = (*it_face_idx);
12988  }
12989 
12990  // Store the nodes for the new shared polylines without
12991  // loops
12992  Vector<std::list<Node*> > final_sorted_nodes_pt;
12993  // Store the boundary elements of the shared polyline
12994  // without loops
12995  Vector<Vector<FiniteElement*> > final_boundary_element_pt;
12996  // Face indexes of the boundary elements without loops
12997  Vector<Vector<int> > final_face_index_element;
12998  // Connection flags (to the left) of the shared boundaries
12999  // without loops
13000  Vector<int> final_bound_id_connection_to_the_left;
13001  // Connection flags (to the right) of the shared boundaries
13002  // without loops
13003  Vector<int> final_bound_id_connection_to_the_right;
13004 
13005  // Break any possible loop created by the shared polyline
13006  break_loops_on_shared_polyline_helper(
13007  shared_boundary_id_start,
13008  sorted_nodes,
13009  tmp_bnd_ele_pt, tmp_face_idx_ele,
13010  bound_id_connection_to_the_left, bound_id_connection_to_the_right,
13011  final_sorted_nodes_pt,
13012  final_boundary_element_pt, final_face_index_element,
13013  final_bound_id_connection_to_the_left,
13014  final_bound_id_connection_to_the_right);
13015 
13016  // Get the number of final sorted nodes
13017  const unsigned n_final_sorted_nodes =
13018  final_sorted_nodes_pt.size();
13019 
13020  // Loop over the list of final sorted nodes
13021  for (unsigned i = 0; i < n_final_sorted_nodes; i++)
13022  {
13023  // --------------------------------------------------------
13024  // Associate the list of sorted nodes with the boundary id
13025  // of the shared boundary that is going to be crated
13026  shared_bnd_id_to_sorted_list_node_pt[shared_boundary_id_start] =
13027  final_sorted_nodes_pt[i];
13028 
13029  // Create the shared polyline and fill the data
13030  // structured associated to it
13031  create_shared_polyline(my_rank, shared_boundary_id_start,
13032  iproc, jproc, final_sorted_nodes_pt[i],
13033  root_edge_bound_id,
13034  final_boundary_element_pt[i],
13035  final_face_index_element[i],
13036  unsorted_polylines_pt,
13037  final_bound_id_connection_to_the_left[i],
13038  final_bound_id_connection_to_the_right[i]);
13039 
13040  // Increase the register for the number of created shared
13041  // polylines
13042  npolylines_counter++;
13043 
13044  // Increase the boundary id (the one that will be used by
13045  // the next shared boundary)
13046  shared_boundary_id_start++;
13047 
13048  } // for (i < n_final_sorted_nodes)
13049 
13050  } // while(nsorted_edges < nedges);
13051 
13052  } // for (jproc < nproc)
13053 
13054  // We already have all the shared polylines (shared boundaries)
13055  // of processor iproc with processor jproc. Now we sort them so
13056  // that they be contiguous and can create polygons.
13057 
13058  // If there are polylines to be sorted then sort them
13059  if (unsorted_polylines_pt[iproc].size() > 0)
13060  {
13061  // Now that we have all the new unsorted polylines on "iproc"
13062  // processor it is time to sort them so they be all contiguous
13063  sort_polylines_helper(unsorted_polylines_pt[iproc],
13064  output_polylines_pt[iproc]);
13065  }
13066 
13067 #ifdef PARANOID
13068  const unsigned nunsorted_polylines_iproc =
13069  unsorted_polylines_pt[iproc].size();
13070 
13071  // Verify that all the polylines have been sorted
13072  unsigned tmp_ntotal_polylines = 0;
13073  // Count the total number of sorted polylines
13074  for (unsigned ii = 0 ; ii < output_polylines_pt[iproc].size(); ii++)
13075  {tmp_ntotal_polylines+= output_polylines_pt[iproc][ii].size();}
13076  if (tmp_ntotal_polylines != nunsorted_polylines_iproc)
13077  {
13078  std::ostringstream error_message;
13079  error_message
13080  <<" The total number of unsorted polylines ("
13081  << nunsorted_polylines_iproc << ") in common with\nprocessor ("
13082  << iproc<< ") is different from the total number of sorted "
13083  << "polylines (" << tmp_ntotal_polylines << ") with\nthe same "
13084  << "proessor\n";
13085  throw OomphLibError(error_message.str(),
13086  OOMPH_CURRENT_FUNCTION,
13087  OOMPH_EXCEPTION_LOCATION);
13088  } // if (tmp_ntotal_polylines != nunsorted_polylines_iproc)
13089 #endif
13090 
13091  } // for (iproc < nproc)
13092 
13093  // Establish the last used boundary id
13094  this->Final_shared_boundary_id = shared_boundary_id_start;
13095 
13096  }
13097 
13098  // ======================================================================
13099  // \short Break any possible loop created by the sorted list of nodes
13100  // that is used to create a new shared polyline
13101  // ======================================================================
13102  template<class ELEMENT>
13104  const unsigned &initial_shd_bnd_id,
13105  std::list<Node*> &input_nodes,
13106  Vector<FiniteElement*> &input_boundary_element_pt,
13107  Vector<int> &input_face_index_element,
13108  const int &input_connect_to_the_left,
13109  const int &input_connect_to_the_right,
13110  Vector<std::list<Node*> > &output_sorted_nodes_pt,
13111  Vector<Vector<FiniteElement*> > &output_boundary_element_pt,
13112  Vector<Vector<int> > &output_face_index_element,
13113  Vector<int> &output_connect_to_the_left,
13114  Vector<int> &output_connect_to_the_right)
13115  {
13116  // Get the left and right node of the current list of sorted nodes
13117  Node* left_node_pt = input_nodes.front();
13118  Node* right_node_pt = input_nodes.back();
13119 
13120  // Temporary storage for list of nodes, boundary elements and face
13121  // element's indexes
13122  Vector<std::list<Node*> > tmp_sub_nodes;
13123  Vector<Vector<FiniteElement*> > tmp_sub_bnd_ele_pt;
13124  Vector<Vector<int> > tmp_sub_face_idx_ele;
13125 
13126  // Iterator for the list of input nodes
13127  std::list<Node*>::iterator it = input_nodes.begin();
13128 
13129  // Counter
13130  unsigned counter = 0;
13131 
13132  // Loop while not all nodes have been done
13133  while(it != input_nodes.end())
13134  {
13135  // Check if the current node is the final one
13136  it++;
13137  // Is the current node the final node?
13138  if (it == input_nodes.end())
13139  {
13140  // Break, add no more nodes
13141  break;
13142  }
13143  else
13144  {
13145  // Restore the iterator
13146  it--;
13147  }
13148 
13149  // Get a list of nonrepeated nodes
13150  std::list<Node*> sub_nodes;
13151  // The temporary vector of boundary elements associated with the
13152  // nodes
13153  Vector<FiniteElement*> sub_bnd_ele_pt;
13154  // The temporary vector of face indexes associated with the
13155  // boundary elements
13156  Vector<int> sub_face_idx_ele;
13157 
13158  // Add the current node to the list
13159  sub_nodes.push_back(*it);
13160 
13161  // Add nodes until found a repeated node (the left or right
13162  // node) or until reaching the end of the list of nodes
13163  do
13164  {
13165  // Go to the next node
13166  ++it;
13167 
13168  // Add the new node
13169  sub_nodes.push_back((*it));
13170 
13171  // Add the boundary elements
13172  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter]);
13173  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter+1]);
13174 
13175  // Add the face indexes
13176  sub_face_idx_ele.push_back(input_face_index_element[counter]);
13177  sub_face_idx_ele.push_back(input_face_index_element[counter+1]);
13178 
13179  // Increase the counter
13180  counter+=2;
13181 
13182  // Continue adding until reaching a repeated node or the end
13183  // of the list of nodes
13184  }while((*it) != left_node_pt &&
13185  (*it) != right_node_pt &&
13186  it != input_nodes.end());
13187 
13188  // Add the sub-set of nodes to the temporary storage
13189  tmp_sub_nodes.push_back(sub_nodes);
13190  // Add the face elements to the temporary storage
13191  tmp_sub_bnd_ele_pt.push_back(sub_bnd_ele_pt);
13192  // Add the face indexes to the temporary storage
13193  tmp_sub_face_idx_ele.push_back(sub_face_idx_ele);
13194 
13195  } // while((*it) != input_nodes.end())
13196 
13197  // --------------------------------------------------
13198  // Now create as many shared boundaries as required
13199 
13200  // Get the number of sub-list of nodes created
13201  const unsigned n_sub_list = tmp_sub_nodes.size();
13202 
13203 #ifdef PARANOID
13204  if (n_sub_list > 3)
13205  {
13206  std::stringstream error_message;
13207  error_message
13208  << "The number of sub-list of nodes created from the shared\n"
13209  << "polyline with loops was (" << n_sub_list << ").\n"
13210  << "We can only handle up to three sub-list of nodes\n";
13211  throw OomphLibError(error_message.str(),
13212  OOMPH_CURRENT_FUNCTION,
13213  OOMPH_EXCEPTION_LOCATION);
13214  }
13215 #endif
13216 
13217  // If there is only one list it may be because there are no loops or
13218  // there is only one loop (a circle)
13219  if (n_sub_list == 1 && (left_node_pt != right_node_pt))
13220  {
13221  // There are no loops, return just after filling the data
13222  // structures
13223 
13224  // This is the base case used most of the times
13225 
13226  // Set the vector of lists of nodes
13227  output_sorted_nodes_pt = tmp_sub_nodes;
13228  // Set the vector of boundary elements
13229  output_boundary_element_pt = tmp_sub_bnd_ele_pt;
13230  // Set the vector of face indexes
13231  output_face_index_element = tmp_sub_face_idx_ele;
13232 
13233  // Set the connection flags, change them by the proper connection
13234  // flag
13235 
13236 #ifdef PARANOID
13237  if (input_connect_to_the_left == -2)
13238  {
13239  std::stringstream error_message;
13240  error_message
13241  << "The connection flag to the left ("
13242  << input_connect_to_the_left << ") indicates a connection\n"
13243  << "with the same polyline.\n However, only one sub-polyline was "
13244  << "found and no loop\nwas identified\n\n";
13245  throw OomphLibError(error_message.str(),
13246  OOMPH_CURRENT_FUNCTION,
13247  OOMPH_EXCEPTION_LOCATION);
13248  }
13249 #endif
13250 
13251  // The left connection flag
13252  if (input_connect_to_the_left == -3)
13253  {
13254  output_connect_to_the_left.push_back(-1);
13255  }
13256  else
13257  {
13258  output_connect_to_the_left.push_back(input_connect_to_the_left);
13259  }
13260 
13261 #ifdef PARANOID
13262  if (input_connect_to_the_right == -2)
13263  {
13264  std::stringstream error_message;
13265  error_message
13266  << "The connection flag to the right ("
13267  << input_connect_to_the_right << ") indicates a connection\n"
13268  << "with the same polyline.\n However, only one sub-polyline was "
13269  << "found and no loop\nwas identified\n\n";
13270  throw OomphLibError(error_message.str(),
13271  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13272  OOMPH_EXCEPTION_LOCATION);
13273  }
13274 #endif
13275 
13276  // The right connection flag
13277  if (input_connect_to_the_right == -3)
13278  {
13279  output_connect_to_the_right.push_back(-1);
13280  }
13281  else
13282  {
13283  output_connect_to_the_right.push_back(input_connect_to_the_right);
13284  }
13285 
13286  // Return inmediately
13287  return;
13288  }
13289 
13290  // The temporary storage for the shared boundary id
13291  unsigned tmp_shd_bnd_id = initial_shd_bnd_id;
13292 
13293  // -----------------------------------------------------------------
13294  // Check all the sub-list of nodes and create two shared boundaries
13295  // from those that make a loop (circle)
13296 
13297  // -----------------------------------------------------------
13298  // Get the left and right node of the first sub-list of nodes
13299  Node* left_sub_node_pt = tmp_sub_nodes[0].front();
13300  Node* right_sub_node_pt = tmp_sub_nodes[0].back();
13301 
13302  // Check if the sub-list of nodes creates a loop (circle)
13303  if (left_sub_node_pt == right_sub_node_pt)
13304  {
13305  // We need to create two shared polylines and therefore increase
13306  // the shared boundary id by two
13307 
13308  // The first and second half of nodes
13309  std::list<Node*> first_half_node_pt;
13310  std::list<Node*> second_half_node_pt;
13311  // The first and second half of boundary elements
13312  Vector<FiniteElement*> first_half_ele_pt;
13313  Vector<FiniteElement*> second_half_ele_pt;
13314  // The first and second half of face indexes
13315  Vector<int> first_half_face_idx;
13316  Vector<int> second_half_face_idx;
13317 
13318  // Get the number of sub-nodes in the sub-list of nodes
13319  const unsigned n_sub_nodes = tmp_sub_nodes[0].size();
13320 
13321  // The number of sub-nodes for the first half of the shared
13322  // boundary
13323  const unsigned n_sub_nodes_half = static_cast<unsigned>(n_sub_nodes / 2.0);
13324 
13325  // Copy as many sub-nodes for the first half of the sub-polyline
13326 
13327  // Iterator to loop over the nodes
13328  std::list<Node*>::iterator it_sub = tmp_sub_nodes[0].begin();
13329 
13330  // Add the first node
13331  first_half_node_pt.push_back(*it_sub);
13332 
13333  // Skip the first node
13334  it_sub++;
13335 
13336  // Counter
13337  unsigned counter_nodes = 0;
13338  unsigned counter2 = 0;
13339 
13340  // Loop to copy the nodes
13341  for (;it_sub != tmp_sub_nodes[0].end(); it_sub++)
13342  {
13343  // Add the sub-node to the first half
13344  first_half_node_pt.push_back(*it_sub);
13345 
13346  // Add the boundary elements of the first half
13347  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
13348  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2+1]);
13349  // Add the face indexes of the first half
13350  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
13351  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2+1]);
13352 
13353  // Increase the counter of added nodes
13354  counter_nodes++;
13355 
13356  // Increase the other counter
13357  counter2+=2;
13358 
13359  if (counter_nodes == n_sub_nodes_half)
13360  {
13361  // Stop adding to the first half of nodes
13362  break;
13363  }
13364 
13365  } // Copy the first half of nodes
13366 
13367  // The second half
13368 
13369  // Add the first node of the second half
13370  second_half_node_pt.push_back(*it_sub);
13371 
13372  // Skip the first node of the second half
13373  it_sub++;
13374 
13375  // Loop to copy the nodes
13376  for (;it_sub != tmp_sub_nodes[0].end(); it_sub++)
13377  {
13378  // Add the sub-node to the first half
13379  second_half_node_pt.push_back(*it_sub);
13380 
13381  // Add the boundary elements of the first half
13382  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
13383  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2+1]);
13384  // Add the face indexes of the first half
13385  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
13386  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2+1]);
13387 
13388  // Increase the other counter
13389  counter2+=2;
13390 
13391  } // Copy the second half of nodes
13392 
13393  // Add the sub-list of nodes to the vector of lists of nodes
13394  output_sorted_nodes_pt.push_back(first_half_node_pt);
13395  output_sorted_nodes_pt.push_back(second_half_node_pt);
13396  // Add the sub-vector of elements to the vector of boundary
13397  // elements
13398  output_boundary_element_pt.push_back(first_half_ele_pt);
13399  output_boundary_element_pt.push_back(second_half_ele_pt);
13400  // Add the sub-vector of face indexes to the vector of face
13401  // indexes
13402  output_face_index_element.push_back(first_half_face_idx);
13403  output_face_index_element.push_back(second_half_face_idx);
13404 
13405  // Set the connection flags, change them by the proper connection
13406  // flag
13407 
13408  // ----------------------------------------------------------------
13409  // Connections flags for the first half
13410 
13411  // The left connection flag
13412 
13413  // Connected with nothing but required to stop adding nodes
13414  if (input_connect_to_the_left == -3)
13415  {
13416  // Set connected to nothing
13417  output_connect_to_the_left.push_back(-1);
13418  }
13419  // Connected with itself
13420  else if (input_connect_to_the_left == -2)
13421  {
13422  // Set connected to nothing, this is the base node
13423  output_connect_to_the_left.push_back(-1);
13424  }
13425  else
13426  {
13427  // Any other value keep it
13428  output_connect_to_the_left.push_back(input_connect_to_the_left);
13429  }
13430 
13431  // The right connection flag
13432 
13433  // Set connected to nothing, this is the base node
13434  output_connect_to_the_right.push_back(-1);
13435 
13436  // Increase the shared boundary id
13437  tmp_shd_bnd_id++;
13438 
13439  // ----------------------------------------------------------------
13440  // Connections flags for the second half
13441 
13442  // The left connection flag
13443 
13444  // Set connected to the previous boundary
13445  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13446 
13447  // The right connection flag
13448 
13449  // Are we in the last sub-list of nodes, if that is the case we
13450  // need to respect the flag assigned to the right
13451  if (n_sub_list == 1)
13452  {
13453  if (input_connect_to_the_right == -3)
13454  {
13455  // Set connected to the previous shared boundary id
13456  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13457  }
13458  else if (input_connect_to_the_right == -2)
13459  {
13460  // Set connected to the previous shared boundary id
13461  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13462  }
13463  else if (input_connect_to_the_right == -1)
13464  {
13465  // Set connected to the previous shared boundary id
13466  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13467  }
13468  else
13469  {
13470  // Any other value keep it
13471  output_connect_to_the_right.push_back(input_connect_to_the_right);
13472  }
13473  } // if (n_sub_list == 1)
13474  else
13475  {
13476  // Set connected to the previous shared boundary id
13477  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13478  }
13479 
13480  // Increase the shared boundary id
13481  tmp_shd_bnd_id++;
13482 
13483  } // if (left_sub_node_pt == right_sub_node_pt)
13484  else
13485  {
13486  // No need to create two boundaries, create only one with the
13487  // sub-list of nodes
13488 
13489  // Add the sub-list of nodes to the vector of lists of nodes
13490  output_sorted_nodes_pt.push_back(tmp_sub_nodes[0]);
13491  // Add the sub-vector of elements to the vector of boundary
13492  // elements
13493  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[0]);
13494  // Add the sub-vector of face indexes to the vector of face
13495  // indexes
13496  output_face_index_element.push_back(tmp_sub_face_idx_ele[0]);
13497 
13498  // Set the connection flags, change them by the proper connection
13499  // flag
13500 
13501  // The left connection flag
13502 
13503  // Connected with nothing but required to stop adding nodes
13504  if (input_connect_to_the_left == -3)
13505  {
13506  // Set to connected to nothing
13507  output_connect_to_the_left.push_back(-1);
13508  }
13509  // Connected with itself
13510  else if (input_connect_to_the_left == -2)
13511  {
13512  // Set connected to the next shared polyline id
13513  output_connect_to_the_left.push_back(tmp_shd_bnd_id+1);
13514  }
13515  else
13516  {
13517  // Any other value keep it
13518  output_connect_to_the_left.push_back(input_connect_to_the_left);
13519  }
13520 
13521  // The right connection flag
13522 
13523  // Set connected to the next shared polyline id
13524  output_connect_to_the_right.push_back(tmp_shd_bnd_id+1);
13525 
13526  // Increase the shared boundary id by one
13527  tmp_shd_bnd_id++;
13528 
13529  } // else if (left_sub_node_pt == right_sub_node_pt)
13530 
13531  // At least two sub-list of nodes were created
13532  if (n_sub_list > 1)
13533  {
13534  // ------------------------------------------------------------
13535  // Get the left and right node of the second sub-list of nodes
13536  left_sub_node_pt = tmp_sub_nodes[1].front();
13537  right_sub_node_pt = tmp_sub_nodes[1].back();
13538 
13539  // Check if the sub-list of nodes creates a loop (circle)
13540  if (left_sub_node_pt == right_sub_node_pt)
13541  {
13542  // We need to create two shared polylines and therefore increase
13543  // the shared boundary id by two
13544 
13545  // The first and second half of nodes
13546  std::list<Node*> first_half_node_pt;
13547  std::list<Node*> second_half_node_pt;
13548  // The first and second half of boundary elements
13549  Vector<FiniteElement*> first_half_ele_pt;
13550  Vector<FiniteElement*> second_half_ele_pt;
13551  // The first and second half of face indexes
13552  Vector<int> first_half_face_idx;
13553  Vector<int> second_half_face_idx;
13554 
13555  // Get the number of sub-nodes in the sub-list of nodes
13556  const unsigned n_sub_nodes = tmp_sub_nodes[1].size();
13557 
13558  // The number of sub-nodes for the first half of the shared
13559  // boundary
13560  const unsigned n_sub_nodes_half = static_cast<unsigned>(n_sub_nodes / 2.0);
13561 
13562  // Copy as many sub-nodes for the first half of the sub-polyline
13563 
13564  // Iterator to loop over the nodes
13565  std::list<Node*>::iterator it_sub = tmp_sub_nodes[1].begin();
13566 
13567  // Add the first node
13568  first_half_node_pt.push_back(*it_sub);
13569 
13570  // Skip the first node
13571  it_sub++;
13572 
13573  // Counter
13574  unsigned counter_nodes = 0;
13575  unsigned counter2 = 0;
13576 
13577  // Loop to copy the nodes
13578  for (;it_sub != tmp_sub_nodes[1].end(); it_sub++)
13579  {
13580  // Add the sub-node to the first half
13581  first_half_node_pt.push_back(*it_sub);
13582  // Add the boundary elements of the first half
13583  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2]);
13584  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2+1]);
13585  // Add the face indexes of the first half
13586  first_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2]);
13587  first_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2+1]);
13588 
13589  // Increase the counter of added nodes
13590  counter_nodes++;
13591 
13592  // Increase the other counter
13593  counter2+=2;
13594 
13595  if (counter_nodes == n_sub_nodes_half)
13596  {
13597  // Stop adding to the first half of nodes
13598  break;
13599  }
13600 
13601  } // Copy the first half of nodes
13602 
13603  // The second half
13604 
13605  // Add the first node of the second half
13606  second_half_node_pt.push_back(*it_sub);
13607 
13608  // Skip the first node of the second half
13609  it_sub++;
13610 
13611  // Loop to copy the nodes
13612  for (;it_sub != tmp_sub_nodes[1].end(); it_sub++)
13613  {
13614  // Add the sub-node to the first half
13615  second_half_node_pt.push_back(*it_sub);
13616  // Add the boundary elements of the first half
13617  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2]);
13618  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2+1]);
13619  // Add the face indexes of the first half
13620  second_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2]);
13621  second_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2+1]);
13622 
13623  // Increase the other counter
13624  counter2+=2;
13625 
13626  } // Copy the second half of nodes
13627 
13628  // Add the sub-list of nodes to the vector of lists of nodes
13629  output_sorted_nodes_pt.push_back(first_half_node_pt);
13630  output_sorted_nodes_pt.push_back(second_half_node_pt);
13631  // Add the sub-vector of elements to the vector of boundary
13632  // elements
13633  output_boundary_element_pt.push_back(first_half_ele_pt);
13634  output_boundary_element_pt.push_back(second_half_ele_pt);
13635  // Add the sub-vector of face indexes to the vector of face
13636  // indexes
13637  output_face_index_element.push_back(first_half_face_idx);
13638  output_face_index_element.push_back(second_half_face_idx);
13639 
13640  // Set the connection flags, change them by the proper
13641  // connection flag
13642 
13643  // --------------------------------------
13644  // Connections flags for the first half
13645 
13646  // The left connection flag
13647 
13648  // Connected to the previous boundary
13649  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13650 
13651  // The right connection flag
13652 
13653  // Set connected to nothing, this is the base node
13654  output_connect_to_the_right.push_back(-1);
13655 
13656  // Increase the shared boundary id
13657  tmp_shd_bnd_id++;
13658 
13659  // --------------------------------------
13660  // Connections flags for the second half
13661 
13662  // The left connection flag
13663 
13664  // Set connected to the previous boundary
13665  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13666 
13667  // The right connection flag
13668 
13669  // Are we in the last sub-list of nodes, if that is the case we
13670  // need to respect the flag assigned to the right
13671  if (n_sub_list == 2)
13672  {
13673  // Connected with nothing
13674  if (input_connect_to_the_right == -1)
13675  {
13676  // Set connected to the previous shared boundary
13677  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13678  }
13679  // Connected with the same boundary
13680  else if (input_connect_to_the_right == -2)
13681  {
13682  // Set connected to the previous shared boundary
13683  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13684  }
13685  // Connetted with nothing but stop adding nodes
13686  else if (input_connect_to_the_right == -3)
13687  {
13688  // Set connected to the previous shared boundary
13689  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13690  }
13691  else
13692  {
13693  // Any other value keep it
13694  output_connect_to_the_right.push_back(input_connect_to_the_right);
13695  }
13696 
13697  // Increase the shared boundary id
13698  tmp_shd_bnd_id++;
13699 
13700  } // if (n_sub_list == 2)
13701 #ifdef PARANOID
13702  else
13703  {
13704  std::stringstream error_message;
13705  error_message
13706  << "The second sub-list of nodes creates a loop but this is not\n"
13707  << "the last list of sub-nodes.\n"
13708  << "This configuration is not supported\n";
13709  throw OomphLibError(error_message.str(),
13710  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13711  OOMPH_EXCEPTION_LOCATION);
13712  }
13713 #endif
13714 
13715  } // if (left_sub_node_pt == right_sub_node_pt)
13716  else
13717  {
13718  // No need to create two boundaries, create only one with the
13719  // sub-list of nodes
13720 
13721  // Add the sub-list of nodes to the vector of lists of nodes
13722  output_sorted_nodes_pt.push_back(tmp_sub_nodes[1]);
13723  // Add the sub-vector of elements to the vector of boundary
13724  // elements
13725  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[1]);
13726  // Add the sub-vector of face indexes to the vector of face
13727  // indexes
13728  output_face_index_element.push_back(tmp_sub_face_idx_ele[1]);
13729 
13730  // Set the connection flags, change them by the proper connection
13731  // flag
13732 
13733  // The left connection flag
13734 
13735  // Set connected to the previous shared boundary id
13736  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13737 
13738  // The right connection flag
13739 
13740  // Are we in the last sub-list of nodes, if that is the case we
13741  // need to respect the flag assigned to the right
13742  if (n_sub_list == 2)
13743  {
13744  // Connected with nothing but required to stop adding nodes
13745  if (input_connect_to_the_right == -3)
13746  {
13747  // Set to connected to nothing
13748  output_connect_to_the_right.push_back(-1);
13749  }
13750 #ifdef PARANOID
13751  // Connected with itself
13752  else if (input_connect_to_the_right == -2)
13753  {
13754  std::stringstream error_message;
13755  error_message
13756  << "The connection flag to the right ("
13757  << input_connect_to_the_right << ") indicates a connection\n"
13758  << "with the same polyline.\n However, the second sub-list of\n"
13759  << "nodes was found not making a loop so no connection with\n"
13760  << "itself should be marked\n\n";
13761  throw OomphLibError(error_message.str(),
13762  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13763  OOMPH_EXCEPTION_LOCATION);
13764  }
13765 #endif
13766  else
13767  {
13768  // Any other value keep it
13769  output_connect_to_the_right.push_back(input_connect_to_the_right);
13770  }
13771  } // if (n_sub_list == 2)
13772  else
13773  {
13774  // Set connected to the next shared boundary id
13775  output_connect_to_the_right.push_back(tmp_shd_bnd_id+1);
13776  } // else if (n_sub_list == 2)
13777 
13778  // Increase the shared boundary id by one
13779  tmp_shd_bnd_id++;
13780 
13781  } // if (left_sub_node_pt == right_sub_node_pt)
13782 
13783  } // if (n_sub_list > 1)
13784 
13785  // Three sub-list of nodes were created
13786  if (n_sub_list > 2)
13787  {
13788  // ------------------------------------------------------------
13789  // Get the left and right node of the third sub-list of nodes
13790  left_sub_node_pt = tmp_sub_nodes[2].front();
13791  right_sub_node_pt = tmp_sub_nodes[2].back();
13792 
13793  // Check if the sub-list of nodes creates a loop (circle)
13794  if (left_sub_node_pt == right_sub_node_pt)
13795  {
13796  // We need to create two shared polylines and therefore increase
13797  // the shared boundary id by two
13798 
13799  // The first and second half of nodes
13800  std::list<Node*> first_half_node_pt;
13801  std::list<Node*> second_half_node_pt;
13802  // The first and second half of boundary elements
13803  Vector<FiniteElement*> first_half_ele_pt;
13804  Vector<FiniteElement*> second_half_ele_pt;
13805  // The first and second half of face indexes
13806  Vector<int> first_half_face_idx;
13807  Vector<int> second_half_face_idx;
13808 
13809  // Get the number of sub-nodes in the sub-list of nodes
13810  const unsigned n_sub_nodes = tmp_sub_nodes[2].size();
13811 
13812  // The number of sub-nodes for the first half of the shared
13813  // boundary
13814  const unsigned n_sub_nodes_half = static_cast<unsigned>(n_sub_nodes / 2.0);
13815 
13816  // Copy as many sub-nodes for the first half of the sub-polyline
13817 
13818  // Iterator to loop over the nodes
13819  std::list<Node*>::iterator it_sub = tmp_sub_nodes[2].begin();
13820 
13821  // Add the first node
13822  first_half_node_pt.push_back(*it_sub);
13823 
13824  // Skip the first node
13825  it_sub++;
13826 
13827  // Counter
13828  unsigned counter_nodes = 0;
13829  unsigned counter2 = 0;
13830 
13831  // Loop to copy the nodes
13832  for (;it_sub != tmp_sub_nodes[2].end(); it_sub++)
13833  {
13834  // Add the sub-node to the first half
13835  first_half_node_pt.push_back(*it_sub);
13836  // Add the boundary elements of the first half
13837  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2]);
13838  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2+1]);
13839  // Add the face indexes of the first half
13840  first_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2]);
13841  first_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2+1]);
13842 
13843  // Increase the counter of added nodes
13844  counter_nodes++;
13845 
13846  // Increase the other counter
13847  counter2+=2;
13848 
13849  if (counter_nodes == n_sub_nodes_half)
13850  {
13851  // Stop adding to the first half of nodes
13852  break;
13853  }
13854 
13855  } // Copy the first half of nodes
13856 
13857  // The second half
13858 
13859  // Add the first node of the second half
13860  second_half_node_pt.push_back(*it_sub);
13861 
13862  // Skip the first node of the second half
13863  it_sub++;
13864 
13865  // Loop to copy the nodes
13866  for (;it_sub != tmp_sub_nodes[2].end(); it_sub++)
13867  {
13868  // Add the sub-node to the first half
13869  second_half_node_pt.push_back(*it_sub);
13870  // Add the boundary elements of the first half
13871  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2]);
13872  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2+1]);
13873  // Add the face indexes of the first half
13874  second_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2]);
13875  second_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2+1]);
13876 
13877  // Increase the other counter
13878  counter2+=2;
13879 
13880  } // Copy the second half of nodes
13881 
13882  // Add the sub-list of nodes to the vector of lists of nodes
13883  output_sorted_nodes_pt.push_back(first_half_node_pt);
13884  output_sorted_nodes_pt.push_back(second_half_node_pt);
13885  // Add the sub-vector of elements to the vector of boundary
13886  // elements
13887  output_boundary_element_pt.push_back(first_half_ele_pt);
13888  output_boundary_element_pt.push_back(second_half_ele_pt);
13889  // Add the sub-vector of face indexes to the vector of face
13890  // indexes
13891  output_face_index_element.push_back(first_half_face_idx);
13892  output_face_index_element.push_back(second_half_face_idx);
13893 
13894  // --------------------------------------
13895  // Connections flags for the first half
13896 
13897  // The left connection flag
13898 
13899  // Connected to the previous shared boundary
13900  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13901 
13902  // The right connection flag
13903 
13904  // Set connected to nothing, this is the base node
13905  output_connect_to_the_right.push_back(-1);
13906 
13907  // Increase the shared boundary id
13908  tmp_shd_bnd_id++;
13909 
13910  // --------------------------------------
13911  // Connections flags for the second half
13912 
13913  // The left connection flag
13914 
13915  // Set connected to the previous boundary
13916  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13917 
13918  // The right connection flag
13919 
13920  if (input_connect_to_the_right == -3)
13921  {
13922  // Set connected to the previous shared boundary id
13923  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13924  }
13925  else if (input_connect_to_the_right == -2)
13926  {
13927  // Set connected to the previous shared boundary id
13928  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13929  }
13930  else if (input_connect_to_the_right == -1)
13931  {
13932  // Set connected to the previous shared boundary id
13933  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13934  }
13935  else
13936  {
13937  // Any other value keep it
13938  output_connect_to_the_right.push_back(input_connect_to_the_right);
13939  }
13940 
13941  // Increase the shared boundary id
13942  tmp_shd_bnd_id++;
13943 
13944  } // if (left_sub_node_pt == right_sub_node_pt)
13945  else
13946  {
13947  // No need to create two boundaries, create only one with the
13948  // sub-list of nodes
13949 
13950  // Add the sub-list of nodes to the vector of lists of nodes
13951  output_sorted_nodes_pt.push_back(tmp_sub_nodes[2]);
13952  // Add the sub-vector of elements to the vector of boundary
13953  // elements
13954  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[2]);
13955  // Add the sub-vector of face indexes to the vector of face
13956  // indexes
13957  output_face_index_element.push_back(tmp_sub_face_idx_ele[2]);
13958 
13959  // Set the connection flags, change them by the proper
13960  // connection flag
13961 
13962  // The left connection flag
13963 
13964  // Set connected to the previous shared boundary id
13965  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13966 
13967  // The right connection flag
13968 
13969  // Connected with nothing but required to stop adding nodes
13970  if (input_connect_to_the_right == -3)
13971  {
13972  std::stringstream error_message;
13973  error_message
13974  << "The connection flag to the right ("
13975  << input_connect_to_the_right << ") indicates 'no connection and\n"
13976  << "stop adding nodes'.\n However, the thrid sub-list of\n"
13977  << "nodes must have a connection to the right with the same\n"
13978  << "shared polyline or with any other polyline\n\n";
13979  throw OomphLibError(error_message.str(),
13980  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13981  OOMPH_EXCEPTION_LOCATION);
13982  }
13983  else if (input_connect_to_the_right == -1)
13984  {
13985  std::stringstream error_message;
13986  error_message
13987  << "The connection flag to the right ("
13988  << input_connect_to_the_right << ") indicates 'no connection.\n"
13989  << "However, the thrid sub-list of nodes must have a connection\n"
13990  << "to the right with the same shared polyline or with any other\n"
13991  << "polyline\n\n";
13992  throw OomphLibError(error_message.str(),
13993  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13994  OOMPH_EXCEPTION_LOCATION);
13995  }
13996  // Connected with itself
13997  else if (input_connect_to_the_right == -2)
13998  {
13999  // Set connected to the previous shared boundary id
14000  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14001  }
14002  else
14003  {
14004  // Any other value keep it
14005  output_connect_to_the_right.push_back(input_connect_to_the_right);
14006  }
14007 
14008  // Increase the shared boundary id by one
14009  tmp_shd_bnd_id++;
14010 
14011  } // if (left_sub_node_pt == right_sub_node_pt)
14012 
14013  } // if (n_sub_list > 2)
14014 
14015  }
14016 
14017  // ======================================================================
14018  // \short Break any possible loop created by the sorted list of nodes
14019  // that is used to create a new shared polyline
14020  // ======================================================================
14021  template<class ELEMENT>
14024  const unsigned &initial_shd_bnd_id,
14025  std::list<Node*> &input_nodes,
14026  Vector<FiniteElement*> &input_boundary_element_pt,
14027  Vector<FiniteElement*> &input_boundary_face_element_pt,
14028  Vector<int> &input_face_index_element,
14029  const int &input_connect_to_the_left,
14030  const int &input_connect_to_the_right,
14031  Vector<std::list<Node*> > &output_sorted_nodes_pt,
14032  Vector<Vector<FiniteElement*> > &output_boundary_element_pt,
14033  Vector<Vector<FiniteElement*> > &output_boundary_face_element_pt,
14034  Vector<Vector<int> > &output_face_index_element,
14035  Vector<int> &output_connect_to_the_left,
14036  Vector<int> &output_connect_to_the_right)
14037  {
14038  // Get the left and right node of the current list of sorted nodes
14039  Node* left_node_pt = input_nodes.front();
14040  Node* right_node_pt = input_nodes.back();
14041 
14042  // Temporary storage for list of nodes, boundary elements, boundary
14043  // face elements and face element's indexes
14044  Vector<std::list<Node*> > tmp_sub_nodes;
14045  Vector<Vector<FiniteElement*> > tmp_sub_bnd_ele_pt;
14046  Vector<Vector<FiniteElement*> > tmp_sub_bnd_face_ele_pt;
14047  Vector<Vector<int> > tmp_sub_face_idx_ele;
14048 
14049  // Iterator for the list of input nodes
14050  std::list<Node*>::iterator it = input_nodes.begin();
14051 
14052  // Counter
14053  unsigned counter = 0;
14054 
14055  // Loop while not all nodes have been done
14056  while(it != input_nodes.end())
14057  {
14058  // Check if the current node is the final one
14059  it++;
14060  // Is the current node the final node?
14061  if (it == input_nodes.end())
14062  {
14063  // Break, add no more nodes
14064  break;
14065  }
14066  else
14067  {
14068  // Restore the iterator
14069  it--;
14070  }
14071 
14072  // Get a list of nonrepeated nodes
14073  std::list<Node*> sub_nodes;
14074  // The temporary vector of boundary elements associated with the
14075  // nodes
14076  Vector<FiniteElement*> sub_bnd_ele_pt;
14077  // The temporary vector of boundary face elements associated with
14078  // the nodes
14079  Vector<FiniteElement*> sub_bnd_face_ele_pt;
14080  // The temporary vector of face indexes associated with the
14081  // boundary elements
14082  Vector<int> sub_face_idx_ele;
14083 
14084  // Add the current node to the list
14085  sub_nodes.push_back(*it);
14086 
14087  // Add nodes until found a repeated node (the left or right
14088  // node) or until reaching the end of the list of nodes
14089  do
14090  {
14091  // Go to the next node
14092  ++it;
14093 
14094  // Add the new node
14095  sub_nodes.push_back((*it));
14096 
14097  // Add the boundary elements
14098  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter]);
14099 
14100  // Add the boundary face elements
14101  sub_bnd_face_ele_pt.push_back(input_boundary_face_element_pt[counter]);
14102 
14103  // Add the face indexes
14104  sub_face_idx_ele.push_back(input_face_index_element[counter]);
14105 
14106  // Increase the counter
14107  counter++;
14108 
14109  // Continue adding until reaching a repeated node or the end
14110  // of the list of nodes
14111  }while((*it) != left_node_pt &&
14112  (*it) != right_node_pt &&
14113  it != input_nodes.end());
14114 
14115  // Add the sub-set of nodes to the temporary storage
14116  tmp_sub_nodes.push_back(sub_nodes);
14117 
14118  // Add the boundary elements to the temporary storage
14119  tmp_sub_bnd_ele_pt.push_back(sub_bnd_ele_pt);
14120  // Add the boundary face elements to the temporary storage
14121  tmp_sub_bnd_face_ele_pt.push_back(sub_bnd_face_ele_pt);
14122  // Add the face indexes to the temporary storage
14123  tmp_sub_face_idx_ele.push_back(sub_face_idx_ele);
14124 
14125  } // while((*it) != input_nodes.end())
14126 
14127  // --------------------------------------------------
14128  // Now create as many shared boundaries as required
14129 
14130  // Get the number of sub-list of nodes created
14131  const unsigned n_sub_list = tmp_sub_nodes.size();
14132 
14133 #ifdef PARANOID
14134  if (n_sub_list > 1)
14135  {
14136  std::stringstream error_message;
14137  error_message
14138  << "The number of sub-list of nodes created from the shared\n"
14139  << "polyline with loops was (" << n_sub_list << ").\n"
14140  << "We can only handle one list which may still contain loops\n"
14141  << "(or repeated nodes)\n";
14142  throw OomphLibError(error_message.str(),
14143  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14144  OOMPH_EXCEPTION_LOCATION);
14145  }
14146 #endif
14147 
14148  // If there is only one list it may be because there are no loops or
14149  // there is only one loop (a circle)
14150  if (n_sub_list == 1 && (left_node_pt != right_node_pt))
14151  {
14152  // There are no loops, return just after filling the data
14153  // structures
14154 
14155  // This is the base case used most of the times
14156 
14157  // Set the vector of lists of nodes
14158  output_sorted_nodes_pt = tmp_sub_nodes;
14159  // Set the vector of boundary elements
14160  output_boundary_element_pt = tmp_sub_bnd_ele_pt;
14161  // Set the vector of boundary face elements
14162  output_boundary_face_element_pt = tmp_sub_bnd_face_ele_pt;
14163  // Set the vector of face indexes
14164  output_face_index_element = tmp_sub_face_idx_ele;
14165 
14166  // Set the connection flags, change them by the proper connection
14167  // flag
14168 
14169 #ifdef PARANOID
14170  if (input_connect_to_the_left == -2)
14171  {
14172  std::stringstream error_message;
14173  error_message
14174  << "The connection flag to the left ("
14175  << input_connect_to_the_left << ") indicates a connection\n"
14176  << "with the same polyline.\n However, only one sub-polyline was "
14177  << "found and no loops\nwere identified\n\n";
14178  throw OomphLibError(error_message.str(),
14179  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14180  OOMPH_EXCEPTION_LOCATION);
14181  }
14182 #endif
14183 
14184  // The left connection flag
14185  if (input_connect_to_the_left == -3)
14186  {
14187  output_connect_to_the_left.push_back(-1);
14188  }
14189  else
14190  {
14191  output_connect_to_the_left.push_back(input_connect_to_the_left);
14192  }
14193 
14194 #ifdef PARANOID
14195  if (input_connect_to_the_right == -2)
14196  {
14197  std::stringstream error_message;
14198  error_message
14199  << "The connection flag to the right ("
14200  << input_connect_to_the_right << ") indicates a connection\n"
14201  << "with the same polyline.\n However, only one sub-polyline was "
14202  << "found and no loops\nwere identified\n\n";
14203  throw OomphLibError(error_message.str(),
14204  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14205  OOMPH_EXCEPTION_LOCATION);
14206  }
14207 #endif
14208 
14209  // The right connection flag
14210  if (input_connect_to_the_right == -3)
14211  {
14212  output_connect_to_the_right.push_back(-1);
14213  }
14214  else
14215  {
14216  output_connect_to_the_right.push_back(input_connect_to_the_right);
14217  }
14218 
14219  // Return immediately
14220  return;
14221  }
14222 
14223  // The temporary storage for the shared boundary id
14224  unsigned tmp_shd_bnd_id = initial_shd_bnd_id;
14225 
14226  // -----------------------------------------------------------------
14227  // Check all the sub-list of nodes and create two shared boundaries
14228  // from those that make a loop (circle)
14229 
14230  // -----------------------------------------------------------
14231  // Get the left and right node of the first sub-list of nodes
14232  Node* left_sub_node_pt = tmp_sub_nodes[0].front();
14233  Node* right_sub_node_pt = tmp_sub_nodes[0].back();
14234 
14235  // Check if the sub-list of nodes creates a loop (circle)
14236  if (left_sub_node_pt == right_sub_node_pt)
14237  {
14238  // We need to create two shared polylines and therefore increase
14239  // the shared boundary id by two
14240 
14241  // The first and second half of nodes
14242  std::list<Node*> first_half_node_pt;
14243  std::list<Node*> second_half_node_pt;
14244  // The first and second half of boundary elements
14245  Vector<FiniteElement*> first_half_ele_pt;
14246  Vector<FiniteElement*> second_half_ele_pt;
14247  // The first and second half of boundary face elements
14248  Vector<FiniteElement*> first_half_ele_face_pt;
14249  Vector<FiniteElement*> second_half_ele_face_pt;
14250  // The first and second half of face indexes
14251  Vector<int> first_half_face_idx;
14252  Vector<int> second_half_face_idx;
14253 
14254  // Get the number of sub-nodes in the sub-list of nodes
14255  const unsigned n_sub_nodes = tmp_sub_nodes[0].size();
14256 
14257  // The number of sub-nodes for the first half of the shared
14258  // boundary
14259  const unsigned n_sub_nodes_half = static_cast<unsigned>(n_sub_nodes / 2.0);
14260 
14261  // Copy as many sub-nodes for the first half of the sub-polyline
14262 
14263  // Iterator to loop over the nodes
14264  std::list<Node*>::iterator it_sub = tmp_sub_nodes[0].begin();
14265 
14266  // Add the first node
14267  first_half_node_pt.push_back(*it_sub);
14268 
14269  // Skip the first node
14270  it_sub++;
14271 
14272  // Counter
14273  unsigned counter_nodes = 0;
14274  unsigned counter2 = 0;
14275 
14276  // Loop to copy the nodes
14277  for (;it_sub != tmp_sub_nodes[0].end(); it_sub++)
14278  {
14279  // Add the sub-node to the first half
14280  first_half_node_pt.push_back(*it_sub);
14281 
14282  // Add the boundary elements of the first half
14283  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
14284  // Add the boundary face elements of the first half
14285  first_half_ele_face_pt.push_back(tmp_sub_bnd_face_ele_pt[0][counter2]);
14286  // Add the face indexes of the first half
14287  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
14288 
14289  // Increase the counter of added nodes
14290  counter_nodes++;
14291 
14292  // Increase the other counter (of the elements/face)
14293  counter2++;
14294 
14295  if (counter_nodes == n_sub_nodes_half)
14296  {
14297  // Stop adding to the first half of nodes
14298  break;
14299  }
14300 
14301  } // Copy the first half of nodes
14302 
14303  // The second half
14304 
14305  // Add the first node of the second half
14306  second_half_node_pt.push_back(*it_sub);
14307 
14308  // Skip the first node of the second half
14309  it_sub++;
14310 
14311  // Loop to copy the nodes
14312  for (;it_sub != tmp_sub_nodes[0].end(); it_sub++)
14313  {
14314  // Add the sub-node to the first half
14315  second_half_node_pt.push_back(*it_sub);
14316 
14317  // Add the boundary elements of the first half
14318  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
14319  // Add the boundary face elements of the first half
14320  second_half_ele_face_pt.push_back(tmp_sub_bnd_face_ele_pt[0][counter2]);
14321  // Add the face indexes of the first half
14322  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
14323 
14324  // Increase the other counter
14325  counter2++;
14326 
14327  } // Copy the second half of nodes
14328 
14329  // Add the sub-list of nodes to the vector of lists of nodes
14330  output_sorted_nodes_pt.push_back(first_half_node_pt);
14331  output_sorted_nodes_pt.push_back(second_half_node_pt);
14332  // Add the sub-vector of elements to the vector of boundary
14333  // elements
14334  output_boundary_element_pt.push_back(first_half_ele_pt);
14335  output_boundary_element_pt.push_back(second_half_ele_pt);
14336  // Add the sub-vector of face elements to the vector of boundary
14337  // elements
14338  output_boundary_face_element_pt.push_back(first_half_ele_face_pt);
14339  output_boundary_face_element_pt.push_back(second_half_ele_face_pt);
14340  // Add the sub-vector of face indexes to the vector of face
14341  // indexes
14342  output_face_index_element.push_back(first_half_face_idx);
14343  output_face_index_element.push_back(second_half_face_idx);
14344 
14345  // Set the connection flags, change them by the proper connection
14346  // flag
14347 
14348  // ----------------------------------------------------------------
14349  // Connections flags for the first half
14350 
14351  // The left connection flag
14352 
14353  // Connected with nothing but required to stop adding nodes
14354  if (input_connect_to_the_left == -3)
14355  {
14356  // Set connected to nothing
14357  output_connect_to_the_left.push_back(-1);
14358  }
14359  // Connected with itself
14360  else if (input_connect_to_the_left == -2)
14361  {
14362  // Set connected to nothing, this is the base node
14363  output_connect_to_the_left.push_back(-1);
14364  }
14365  else
14366  {
14367  // Any other value keep it
14368  output_connect_to_the_left.push_back(input_connect_to_the_left);
14369  }
14370 
14371  // The right connection flag
14372 
14373  // Set connected to nothing, this is the base node
14374  output_connect_to_the_right.push_back(-1);
14375 
14376  // Increase the shared boundary id
14377  tmp_shd_bnd_id++;
14378 
14379  // ----------------------------------------------------------------
14380  // Connections flags for the second half
14381 
14382  // The left connection flag
14383 
14384  // Set connected to the previous boundary
14385  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
14386 
14387  // The right connection flag
14388 
14389  // Are we in the last sub-list of nodes, if that is the case we
14390  // need to respect the flag assigned to the right
14391  if (n_sub_list == 1)
14392  {
14393  if (input_connect_to_the_right == -3)
14394  {
14395  // Set connected to the previous shared boundary id
14396  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14397  }
14398  else if (input_connect_to_the_right == -2)
14399  {
14400  // Set connected to the previous shared boundary id
14401  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14402  }
14403  else if (input_connect_to_the_right == -1)
14404  {
14405  // Set connected to the previous shared boundary id
14406  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14407  }
14408  else
14409  {
14410  // Any other value keep it
14411  output_connect_to_the_right.push_back(input_connect_to_the_right);
14412  }
14413  } // if (n_sub_list == 1)
14414  else
14415  {
14416  // Set connected to the previous shared boundary id
14417  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14418  }
14419 
14420  // Increase the shared boundary id
14421  tmp_shd_bnd_id++;
14422 
14423  } // if (left_sub_node_pt == right_sub_node_pt)
14424 #ifdef PARANOID
14425  else
14426  {
14427  std::stringstream error_message;
14428  error_message
14429  << "The initial and final node in the current shared polyline are not\n"
14430  << "the same and the number of sublists is ("<< n_sub_list << ").\n"
14431  << "We can not handle more than one sublist in the method to break\n"
14432  << "loops at the load balance stage\n\n";
14433  throw OomphLibError(error_message.str(),
14434  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14435  OOMPH_EXCEPTION_LOCATION);
14436  }
14437 #endif
14438 
14439  }
14440 
14441  // ======================================================================
14442  // \short Create the shared polyline and fill the data structured
14443  // that keep all the information associated with the creationg of the
14444  // shared boundary
14445  // ======================================================================
14446  template<class ELEMENT>
14448  create_shared_polyline(const unsigned &my_rank,
14449  const unsigned &shd_bnd_id,
14450  const unsigned &iproc,
14451  const unsigned &jproc,
14452  std::list<Node*> &sorted_nodes,
14453  const int &root_edge_bnd_id,
14454  Vector<FiniteElement*> &bulk_bnd_ele_pt,
14455  Vector<int> &face_index_ele,
14457  &unsorted_polylines_pt,
14458  const int &connect_to_the_left_flag,
14459  const int &connect_to_the_right_flag)
14460  {
14461  // ----------------------------------------------------------------
14462  // Associate the shared boundary with the respective processors
14463  // ----------------------------------------------------------------
14464 
14465  // Setup the global look-up scheme, where all processors know the
14466  // associations of others processors and the shared boundaries they
14467  // created
14468 
14469  // Set up the boundary shared by "iproc" with "jproc" processor
14470  Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
14471 
14472  // Set up the boundary shared by "jproc" with "iproc" processor
14473  Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
14474 
14475  // Specify the processors involved on the creation of the shared
14476  // boundary
14477  Vector<unsigned> processors(2);
14478  processors[0] = iproc;
14479  processors[1] = jproc;
14480  Shared_boundary_from_processors[shd_bnd_id] = processors;
14481 
14482  // ----------------------------------------------------------------
14483  // If one of the processor associated with the shared boundary is
14484  // the current processor then it needs to create a polyline from the
14485  // input sorted nodes, other processors can skip this part
14486  if (iproc == my_rank || jproc == my_rank)
14487  {
14488  // ------------------------------------------------------------
14489  // Create a vertices representation from the sorted nodes list
14490  // ------------------------------------------------------------
14491 
14492  // Get the number of nodes on the list
14493  const unsigned n_nodes = sorted_nodes.size();
14494  // The vector to store the vertices (assign space)
14495  Vector<Vector<double> > vertices(n_nodes);
14496 
14497  // Copy the vertices from the nodes
14498  unsigned counter = 0;
14499 
14500  for (std::list<Node*>::iterator it = sorted_nodes.begin();
14501  it != sorted_nodes.end(); it++)
14502  {
14503  vertices[counter].resize(2);
14504  vertices[counter][0] = (*it)->x(0);
14505  vertices[counter][1] = (*it)->x(1);
14506  counter++;
14507  }
14508 
14509  // ---------------------------------------------
14510  // Create the polyline from the input vertices
14511  // ---------------------------------------------
14512  TriangleMeshPolyLine *polyline_pt =
14513  new TriangleMeshPolyLine(vertices, shd_bnd_id);
14514 
14515  // ---------------------------------------------
14516  // Establish the internal boundary information
14517  // ---------------------------------------------
14518 
14519  // Check if the shared boundary is overlapping (or is part) of an
14520  // internal boundary
14521  if (root_edge_bnd_id != -1)
14522  {
14523  // If the shared boundary is part of an internal boundary then
14524  // mark the shared boundary
14525  Shared_boundary_overlaps_internal_boundary[shd_bnd_id] =
14526  static_cast<unsigned>(root_edge_bnd_id);
14527  } // if (root_edge_bnd_id != -1)
14528 
14529  // ---------------------------------------------
14530  // Store the boundary elements and face indexes
14531  // ---------------------------------------------
14532 
14533  // Store the shared boundary elements
14534  const unsigned n_shared_boundary_elements = bulk_bnd_ele_pt.size();
14535 #ifdef PARANOID
14536  // Check that the number of shared boundy elements is the same as
14537  // the number of face indexes
14538  const unsigned n_face_index = face_index_ele.size();
14539  if (n_shared_boundary_elements != n_face_index)
14540  {
14541  std::ostringstream error_message;
14542  error_message
14543  << "The number of shared boundary elements is different from the\n"
14544  << "number of face indexes associated to the shared boundary\n"
14545  << "elements\n"
14546  << "Number of shared boundary elements: ("
14547  << n_shared_boundary_elements << ")\n"
14548  << "Number of face indexes: (" << n_face_index << ")\n\n";
14549  throw OomphLibError(error_message.str(),
14550  "TriangleMesh::create_shared_polyline()",
14551  OOMPH_EXCEPTION_LOCATION);
14552  } // if (n_shared_boundary_elements != n_face_index)
14553 #endif
14554 
14555  // Add the shared boundary elements and their respective face
14556  // indexes to their permanent containers
14557  for (unsigned i = 0 ; i < n_shared_boundary_elements; i++)
14558  {
14559  add_shared_boundary_element(shd_bnd_id, bulk_bnd_ele_pt[i]);
14560  add_face_index_at_shared_boundary(shd_bnd_id, face_index_ele[i]);
14561  } // for (i < nshared_boundary_elements)
14562 
14563  // Store the shared boundary nodes
14564  for (std::list<Node*>::iterator it = sorted_nodes.begin();
14565  it != sorted_nodes.end(); it++)
14566  {
14567  add_shared_boundary_node(shd_bnd_id, (*it));
14568  } // for (it != sorted_nodes.end())
14569 
14570  // ----------------------------------------------------------
14571  // Create additional look-up schemes for the shared boundary
14572  // ----------------------------------------------------------
14573 
14574  // Updates bnd_id <---> curve section map
14575  this->Boundary_curve_section_pt[shd_bnd_id] = polyline_pt;
14576 
14577  // Check the size of the unsorted_polylines_pt structure. This
14578  // will have n_procs = 1 when it was called from the
14579  // create_new_shared_boundaries() methods
14580  const unsigned n_procs = unsorted_polylines_pt.size();
14581  if (n_procs > 1)
14582  {
14583  // Add the new created polyline to the list of unsorted
14584  // polylines
14585  unsorted_polylines_pt[iproc].push_back(polyline_pt);
14586 
14587  // ... do this on both processors involved in the creation of
14588  // the shared boundary
14589  unsorted_polylines_pt[jproc].push_back(polyline_pt);
14590  }
14591  else
14592  {
14593  // Add the new created polyline to the list of unsorted
14594  // polylines
14595  unsorted_polylines_pt[0].push_back(polyline_pt);
14596  }
14597 
14598  // Mark the polyline for deletion (when calling destructor)
14599  this->Free_curve_section_pt.insert(polyline_pt);
14600 
14601  // ----------------------------
14602  // Set connection information
14603  // ----------------------------
14604 
14605  // Check that the flags are correct, no connection or the boundary
14606  // id of the boundary to connect
14607 #ifdef PARANOID
14608  // Is the shared polyline not connected to the left
14609  if (connect_to_the_left_flag < 0)
14610  {
14611  // If not connected then should be specified by -1
14612  if (connect_to_the_left_flag != -1)
14613  {
14614  std::ostringstream error_message;
14615  error_message
14616  << "The only accepted values for the connection flags are:\n"
14617  << "POSITIVE values or -1, any other value is rejected, please\n"
14618  << "check that you previously called the methods to deal with\n"
14619  << "other flag values\n"
14620  << "The current flag value for connection to the left is: ("
14621  << connect_to_the_left_flag<<")\n\n";
14622  throw OomphLibError(error_message.str(),
14623  "TriangleMesh::create_shared_polyline()",
14624  OOMPH_EXCEPTION_LOCATION);
14625  } // if (connect_to_the_left_flag != -1)
14626  } // if (connect_to_the_left_flag < 0)
14627 
14628  // Is the shared polyline not connected to the right
14629  if (connect_to_the_right_flag < 0)
14630  {
14631  // If not connected then should be specified by -1
14632  if (connect_to_the_right_flag != -1)
14633  {
14634  std::ostringstream error_message;
14635  error_message
14636  << "The only accepted values for the connection flags are:\n"
14637  << "POSITIVE values or -1, any other value is rejected, please\n"
14638  << "check that you previously called the methods to deal with\n"
14639  << "other flag values\n"
14640  << "The current flag value for connection to the right is: ("
14641  << connect_to_the_right_flag<<")\n\n";
14642  throw OomphLibError(error_message.str(),
14643  "TriangleMesh::create_shared_polyline()",
14644  OOMPH_EXCEPTION_LOCATION);
14645  } // if (connect_to_the_right_flag != -1)
14646  } // if (connect_to_the_right_flag < 0)
14647 #endif
14648 
14649  // Set the connection to the left
14650  if (connect_to_the_left_flag != -1)
14651  {
14652  // Get the unsigned version of the boundary id to the left
14653  const unsigned bnd_id_connection_to_the_left =
14654  static_cast<unsigned>(connect_to_the_left_flag);
14655  // Set the initial vertex as connected
14656  polyline_pt->set_initial_vertex_connected();
14657  // Set the initial vertex connected boundary id
14658  polyline_pt->initial_vertex_connected_bnd_id() =
14659  bnd_id_connection_to_the_left;
14660  // Set the chunk number to zero
14661  polyline_pt->initial_vertex_connected_n_chunk() = 0;
14662 
14663  } // if (connect_to_the_left_flag != -1)
14664 
14665  // Set the connection to the right
14666  if (connect_to_the_right_flag != -1)
14667  {
14668  // Get the unsigned version of the boundary id to the right
14669  const unsigned bnd_id_connection_to_the_right =
14670  static_cast<unsigned>(connect_to_the_right_flag);
14671  // Set the final vertex as connected
14672  polyline_pt->set_final_vertex_connected();
14673  // Set the final vertex connected boundary id
14674  polyline_pt->final_vertex_connected_bnd_id() =
14675  bnd_id_connection_to_the_right;
14676  // Set the chunk number to zero
14677  polyline_pt->final_vertex_connected_n_chunk() = 0;
14678 
14679  } // if (connect_to_the_right_flag != -1)
14680 
14681  } // if (iproc == my_rank || jproc == my_rank)
14682 
14683  }
14684 
14685  //======================================================================
14686  /// \short Reset the boundary elements info. after load balance have
14687  /// taken place
14688  //======================================================================
14689  template <class ELEMENT>
14693  &ntmp_boundary_elements_in_region,
14694  Vector<FiniteElement*> &deleted_elements)
14695  {
14696  // Get the number of boundaries
14697  const unsigned nbound = this->nboundary();
14698 
14699  // Are there regions?
14700  const unsigned n_regions = this->nregion();
14701 
14702  // Loop over the boundaries
14703  for (unsigned b = 0; b < nbound; b++)
14704  {
14705  // Get the boundary elements and back them up
14706  // -----------------------------------------------------------------
14707  // Get the number of boundary elements (mixed with the old and new)
14708  const unsigned nbound_ele = this->nboundary_element(b);
14709  // Back-up the boundary elements
14710  Vector<FiniteElement*> backed_up_boundary_element_pt(nbound_ele);
14711  Vector<int> backed_up_face_index_at_boundary(nbound_ele);
14712  for (unsigned e = 0; e < nbound_ele; e++)
14713  {
14714  // Get the old boundary element
14715  backed_up_boundary_element_pt[e] = this->boundary_element_pt(b, e);
14716  // Get the old face index
14717  backed_up_face_index_at_boundary[e] =
14718  this->face_index_at_boundary(b, e);
14719  } // for (n < nold_boundary_elements)
14720 
14721  // Back up the elements in boundary for each region
14723  backed_up_boundary_region_element_pt(n_regions);
14724  Vector<Vector<int> > backed_up_face_index_at_boundary_region(n_regions);
14725 
14726  // Loop over the regions and back up the boundary elements in
14727  // regions
14728  for (unsigned ir = 0; ir < n_regions; ir++)
14729  {
14730  // Get the region id
14731  const unsigned region_id =
14732  static_cast<unsigned>(this->region_attribute(ir));
14733  // Get the number of boundary region elements (mixed old and new)
14734  const unsigned nbnd_region_ele =
14735  this->nboundary_element_in_region(b, region_id);
14736 
14737  // Loop over the elements in the region
14738  for (unsigned e = 0; e < nbnd_region_ele; e++)
14739  {
14740  // Get the old boundary region element
14741  backed_up_boundary_region_element_pt[ir][e] =
14742  this->boundary_element_in_region_pt(b, region_id, e);
14743 
14744  // Get the old face index
14745  backed_up_face_index_at_boundary_region[ir][e] =
14746  this->face_index_at_boundary_in_region(b, region_id, e);
14747  } // for (e < nbnd_region_ele)
14748 
14749  } // for (ir < n_regions)
14750 
14751  // Clean all previous storages
14752  this->Boundary_element_pt[b].clear();
14753  this->Face_index_at_boundary[b].clear();
14754  if (n_regions > 0)
14755  {
14756  this->Boundary_region_element_pt[b].clear();
14757  this->Face_index_region_at_boundary[b].clear();
14758  }
14759 
14760  // -------------------------------------------------------------------
14761  // Now copy only the elements that are still alive, from those before
14762  // the re-establishment of halo and haloed elements
14763  // -------------------------------------------------------------------
14764  // Start with the boundary elements
14765  // Get the old number of boundary elements
14766  const unsigned nold_bnd_ele = ntmp_boundary_elements[b];
14767  // Loop over the boundary elements and check those still alive
14768  for (unsigned e = 0; e < nold_bnd_ele; e++)
14769  {
14770  FiniteElement* tmp_ele_pt = backed_up_boundary_element_pt[e];
14771  // Include only those elements still alive
14773  std::find(deleted_elements.begin(),
14774  deleted_elements.end(),
14775  tmp_ele_pt);
14776  // Only copy thoes elements not found on the deleted elements
14777  // container
14778  if (it == deleted_elements.end())
14779  {
14780  FiniteElement* add_ele_pt = backed_up_boundary_element_pt[e];
14781  this->Boundary_element_pt[b].push_back(add_ele_pt);
14782  const int face_index = backed_up_face_index_at_boundary[e];
14783  this->Face_index_at_boundary[b].push_back(face_index);
14784  } // if (tmp_ele_pt != 0)
14785 
14786  } // for (n < nold_bnd_ele)
14787 
14788  // ... continue with the boundary elements in specific regions
14789 
14790  // Loop over the regions
14791  for (unsigned ir = 0; ir < n_regions; ir++)
14792  {
14793  // Get the region id
14794  const unsigned region_id =
14795  static_cast<unsigned>(this->region_attribute(ir));
14796 
14797  // Get the old number of boundary elements in region
14798  const unsigned nold_bnd_region_ele =
14799  ntmp_boundary_elements_in_region[b][ir];
14800 
14801  // Loop over the boundary region elements and check those still
14802  // alive
14803  for (unsigned e = 0; e < nold_bnd_region_ele; e++)
14804  {
14805  // Get the element
14806  FiniteElement* tmp_ele_pt =
14807  backed_up_boundary_region_element_pt[ir][e];
14808  // Include only those elements still alive
14810  std::find(deleted_elements.begin(),
14811  deleted_elements.end(),
14812  tmp_ele_pt);
14813  // Only copy those elements not found on the deleted elements
14814  // container
14815  if (it == deleted_elements.end())
14816  {
14817  FiniteElement* add_ele_pt =
14818  backed_up_boundary_region_element_pt[ir][e];
14819  this->Boundary_region_element_pt[b][region_id].push_back(add_ele_pt);
14820  const int face_index = backed_up_face_index_at_boundary_region[ir][e];
14821  this->Face_index_region_at_boundary[b][region_id].
14822  push_back(face_index);
14823  } // if (tmp_ele_pt != 0)
14824 
14825  } // for (n < nbound_ele)
14826 
14827  } // for (ir < n_regions)
14828 
14829  // ----------------------------------------------------------------
14830  // Now copy all those elements created after the re-establishment
14831  // of halo and haloed elements
14832  // ----------------------------------------------------------------
14833  // Loop over the boundary elements
14834  for (unsigned e = nold_bnd_ele; e < nbound_ele; e++)
14835  {
14836  FiniteElement* add_ele_pt = backed_up_boundary_element_pt[e];
14837  this->Boundary_element_pt[b].push_back(add_ele_pt);
14838  const int face_index = backed_up_face_index_at_boundary[e];
14839  this->Face_index_at_boundary[b].push_back(face_index);
14840  } // for (e < nbound_ele)
14841 
14842  // Now add the boundary elements in regions
14843 
14844  // Loop over the regions
14845  for (unsigned ir = 0; ir < n_regions; ir++)
14846  {
14847  // Get the region id
14848  const unsigned region_id =
14849  static_cast<unsigned>(this->region_attribute(ir));
14850 
14851  // Get the old number of boundary elements in region
14852  const unsigned nold_bnd_region_ele =
14853  ntmp_boundary_elements_in_region[b][ir];
14854 
14855  // Get the new number of boundary elements in region
14856  const unsigned nbnd_region_ele =
14857  this->nboundary_element_in_region(b, region_id);
14858 
14859  // Loop over the boundary region elements and check those still
14860  // alive
14861  for (unsigned e = nold_bnd_region_ele; e < nbnd_region_ele; e++)
14862  {
14863  FiniteElement* add_ele_pt = backed_up_boundary_region_element_pt[ir][e];
14864  this->Boundary_region_element_pt[b][region_id].push_back(add_ele_pt);
14865  const int face_index = backed_up_face_index_at_boundary_region[ir][e];
14866  this->Face_index_region_at_boundary[b][region_id].push_back(face_index);
14867  } // for (e < nbnd_region_ele)
14868 
14869  } // for (ir < n_regions)
14870 
14871  } // for (b < nbound)
14872 
14873  // Lookup scheme has now been setup yet
14874  Lookup_for_elements_next_boundary_is_setup=true;
14875 
14876  }
14877 
14878 #endif // OOMPH_HAS_MPI
14879 
14880 #ifdef OOMPH_HAS_TRIANGLE_LIB
14881 
14882 //========================================================================
14883 /// Build a new TriangulateIO object based on target areas specified
14884 //========================================================================
14885 template <class ELEMENT>
14887  TriangulateIO& triangulate_io,
14888  const Vector<double>& target_area,
14889  struct TriangulateIO& triangle_refine)
14890  {
14891 
14892  // Initialize
14894 
14895  // Store the global number of vertices and segments
14896  // in the list
14897  unsigned n_points = triangulate_io.numberofpoints;
14898  triangle_refine.numberofpoints=n_points;
14899 
14900  unsigned n_segments=triangulate_io.numberofsegments;
14901  triangle_refine.numberofsegments=n_segments;
14902 
14903  // Initialization of the TriangulateIO objects to store the values
14904  triangle_refine.pointlist =
14905  (double *) malloc(triangulate_io.numberofpoints * 2 * sizeof(double));
14906  triangle_refine.pointmarkerlist =
14907  (int *) malloc(triangulate_io.numberofpoints * sizeof(int));
14908  triangle_refine.segmentlist =
14909  (int *) malloc(triangulate_io.numberofsegments * 2 * sizeof(int));
14910  triangle_refine.segmentmarkerlist =
14911  (int *) malloc(triangulate_io.numberofsegments * sizeof(int));
14912 
14913  // Storing the point's coordinates in the list
14914  // and in two vectors with x and y coordinates
14915  Vector<double> x_coord (n_points);
14916  Vector<double> y_coord (n_points);
14917 
14918  for(unsigned count_point=0;count_point<n_points*2;count_point++)
14919  {
14920  triangle_refine.pointlist[count_point]=
14921  triangulate_io.pointlist[count_point];
14922 
14923  // Even vaules represent the x coordinate
14924  // Odd values represent the y coordinate
14925  if (count_point%2==0)
14926  {
14927  x_coord[count_point/2] = triangulate_io.pointlist[count_point];
14928  }
14929  else
14930  {
14931  y_coord[(count_point-1)/2] = triangulate_io.pointlist[count_point];
14932  }
14933  }
14934 
14935  // Store the point's markers in the list
14936  for(unsigned count_marker=0;count_marker<n_points;count_marker++)
14937  {
14938  triangle_refine.pointmarkerlist[count_marker]=
14939  triangulate_io.pointmarkerlist[count_marker];
14940  }
14941 
14942  // Storing the segment's edges in the list
14943  for(unsigned count_seg=0;count_seg<n_segments*2;count_seg++)
14944  {
14945  triangle_refine.segmentlist[count_seg]=
14946  triangulate_io.segmentlist[count_seg];
14947  }
14948 
14949  // Store the segment's markers in the list
14950  for(unsigned count_markers=0;count_markers<n_segments;count_markers++)
14951  {
14952  triangle_refine.segmentmarkerlist[count_markers]=
14953  triangulate_io.segmentmarkerlist[count_markers];
14954  }
14955 
14956  // Store the hole's center coordinates
14957  unsigned n_holes = triangulate_io.numberofholes;
14958  triangle_refine.numberofholes = n_holes;
14959 
14960  triangle_refine.holelist =
14961  (double*) malloc(triangulate_io.numberofholes * 2 * sizeof(double));
14962 
14963  // Loop over the holes to get centre coords
14964  for(unsigned count_hole=0;count_hole<n_holes*2;count_hole++)
14965  {
14966  triangle_refine.holelist[count_hole] = triangulate_io.holelist[count_hole];
14967  }
14968 
14969  // Store the triangles values
14970  unsigned n_triangles = triangulate_io.numberoftriangles;
14971  triangle_refine.numberoftriangles = n_triangles;
14972 
14973 #ifdef PARANOID
14974  if (n_triangles!=target_area.size())
14975  {
14976  std::stringstream err;
14977  err << "Number of triangles in triangulate_io="
14978  << n_triangles << " doesn't match\n"
14979  << "size of target area vector ("
14980  << target_area.size() << ")\n";
14981  throw OomphLibError(
14982  err.str(),
14983  OOMPH_CURRENT_FUNCTION,
14984  OOMPH_EXCEPTION_LOCATION);
14985  }
14986 #endif
14987 
14988  unsigned n_corners = triangulate_io.numberofcorners;
14989  triangle_refine.numberofcorners = n_corners;
14990 
14991  triangle_refine.trianglelist =
14992  (int *) malloc(triangulate_io.numberoftriangles * 3 * sizeof(int));
14993 
14994  // Store the triangle's corners in the list and get element sizes
14995  for(unsigned count_tri=0;count_tri<n_triangles*3;count_tri++)
14996  {
14997  triangle_refine.trianglelist[count_tri]=
14998  triangulate_io.trianglelist[count_tri];
14999  }
15000 
15001  // Store the triangle's area in the list
15002  triangle_refine.trianglearealist =
15003  (double *) malloc(triangulate_io.numberoftriangles * sizeof(double));
15004  for(unsigned count_area=0;count_area<n_triangles;count_area++)
15005  {
15006  triangle_refine.trianglearealist[count_area]=target_area[count_area];
15007  }
15008 
15009  // Store the triangles attributes in the list
15010  triangle_refine.numberoftriangleattributes =
15011  triangulate_io.numberoftriangleattributes;
15012 
15013  triangle_refine.triangleattributelist =
15014  (double *) malloc(
15015  triangulate_io.numberoftriangles *
15016  triangulate_io.numberoftriangleattributes * sizeof(double));
15017  for(unsigned count_attribute=0;
15018  count_attribute<(n_triangles*triangulate_io.numberoftriangleattributes);
15019  count_attribute++)
15020  {
15021  triangle_refine.triangleattributelist[count_attribute] =
15022  triangulate_io.triangleattributelist[count_attribute];
15023  }
15024 
15025  }
15026 
15027 #ifdef OOMPH_HAS_MPI
15028 
15029  // ===================================================================
15030  // The comparison class for the map that sorts the nodes on the
15031  // shared boundary (using a lexicographic order)
15032  // ===================================================================
15033  struct classcomp
15034  {
15035 
15036  // Tolerance for lower-left comparison
15037  static double Tol;
15038 
15039 
15040  // Comparison operator for "lower left" ordering
15041  bool operator() (const std::pair<double, double> &lhs,
15042  const std::pair<double, double> &rhs) const
15043  {
15044  double diff_y=lhs.second-rhs.second;
15045  if (diff_y<-Tol) // (lhs.second < rhs.second)
15046  {
15047  return true;
15048  }
15049  else
15050  {
15051  // Are they "equal" with 1.0e-14 tolerance?
15052  if (diff_y<Tol) // (lhs.second == rhs.second)
15053  {
15054 #ifdef PARANOID
15055  double diff_x=lhs.first-rhs.first;
15056  if (fabs(diff_x)<Tol)
15057  {
15058  std::ostringstream warning_message;
15059  warning_message
15060  << "Dodgy \"lower left\" (lexicographic) comparison "
15061  << "of points with cooordinates: "
15062  << " lhs = ( " << lhs.first << " , " << lhs.second << " ) \n"
15063  << " rhs = ( " << rhs.first << " , " << rhs.second << " ) \n"
15064  << "x and y coordinates differ by less than tolerance!\n"
15065  << "diff_x = " << diff_x << "\n"
15066  << "diff_y = " << diff_y << "\n"
15067  << "Tol = " << Tol << "\n";
15068  OomphLibError(warning_message.str(),
15069  OOMPH_CURRENT_FUNCTION,
15070  OOMPH_EXCEPTION_LOCATION);
15071  }
15072 #endif
15073  if (lhs.first < rhs.first)
15074  {
15075  return true;
15076  }
15077  else
15078  {
15079  return false;
15080  }
15081  }
15082  else
15083  {
15084  return false;
15085  }
15086  }
15087 
15088 
15089 
15090  // if (lhs.second < rhs.second)
15091  // {
15092  // return true;
15093  // }
15094  // else
15095  // {
15096  // // // Are "equal" with 1.0e-14 tolerance
15097  // // if (lhs.second - rhs.second < 1.0e-14)
15098  // // Are equal?
15099  // if (lhs.second == rhs.second)
15100  // {
15101  // if (lhs.first < rhs.first)
15102  // {
15103  // return true;
15104  // }
15105  // else
15106  // {
15107  // return false;
15108  // }
15109  // }
15110  // else
15111  // {
15112  // return false;
15113  // }
15114  // }
15115 
15116 
15117  }
15118 
15119  } Bottom_left_sorter; // struct classcomp
15120 
15121 
15122  // Assign value for tolerance
15123  double classcomp::Tol=1.0e-14;
15124 
15125 
15126  //======================================================================
15127  // Sort the nodes on shared boundaries so that the processors that share
15128  // a boundary agree with the order of the nodes on the boundary
15129  //======================================================================
15130  template <class ELEMENT>
15132  {
15133  // Get the shared boundaries in this processor
15134  Vector<unsigned> my_rank_shared_boundaries_ids;
15135  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
15136 
15137  // Get the number of shared boundaries
15138  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
15139 
15140  // Loop over the shared boundaries
15141  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
15142  {
15143  // A map is used to sort the nodes using their coordinates as the key
15144  // of the map
15145  //std::map<std::pair<double, double>, Node*> sorted_nodes_pt;
15146  std::map<std::pair<double, double>, Node*, classcomp> sorted_nodes_pt;
15147 
15148 
15149 #ifdef PARANOID
15150 
15151  // Check min distance between nodes; had better be less than the
15152  // tolerance used for the bottom left sorting
15153  double min_distance_squared=DBL_MAX;
15154 
15155 #endif
15156 
15157  // Get the boundary id
15158  const unsigned b = my_rank_shared_boundaries_ids[i];
15159 
15160  // Get the number of nodes on the current boundary
15161  const unsigned nbnd_node = this->nshared_boundary_node(b);
15162 
15163  // Go through all the nodes on the boundary and temporarily store
15164  // them on the map container
15165  for (unsigned i_node = 0; i_node < nbnd_node; i_node++)
15166  {
15167  Node* node_pt = this->shared_boundary_node_pt(b, i_node);
15168  std::pair<double, double> vertex = std::make_pair(node_pt->x(0),
15169  node_pt->x(1));
15170  sorted_nodes_pt[vertex] = node_pt;
15171 
15172 
15173 
15174 #ifdef PARANOID
15175 
15176  // Check for minimum distance
15177  for (unsigned j_node = 0; j_node < nbnd_node; j_node++)
15178  {
15179  if (i_node!=j_node)
15180  {
15181  Node* node2_pt = this->shared_boundary_node_pt(b, j_node);
15182 
15183  // Squared distance
15184  double squared_distance=0.0;
15185  for (unsigned ii=0;ii<2;ii++)
15186  {
15187  squared_distance+=
15188  (node_pt->x(ii)-node2_pt->x(ii))*
15189  (node_pt->x(ii)-node2_pt->x(ii));
15190  }
15191  if (squared_distance<min_distance_squared)
15192  {
15193  min_distance_squared=squared_distance;
15194  }
15195  }
15196  }
15197 
15198  if (sqrt(min_distance_squared)<Bottom_left_sorter.Tol)
15199  {
15200  std::ostringstream warning_message;
15201  warning_message
15202  << "Minimum distance between nodes on boundary " << b << "\n"
15203  << "is " << sqrt(min_distance_squared) << " which is less than "
15204  << "Bottom_left_sorter.Tol = " << Bottom_left_sorter.Tol << "\n"
15205  << "This may screw up the ordering of the nodes on shared boundaries\n";
15206  OomphLibWarning(warning_message.str(),
15207  OOMPH_CURRENT_FUNCTION,
15208  OOMPH_EXCEPTION_LOCATION);
15209  }
15210 
15211 #endif
15212 
15213  }
15214 
15215  unsigned counter = 0;
15216  // Resize the sorted shared boundary node vector
15217  this->Sorted_shared_boundary_node_pt[b].resize(nbnd_node);
15218 
15219  // Now go through the map container, get the elements and store their
15220  // members on the Sorted_shared_boundary_node_pt container
15221  // The map has already sorted the nodes, now they keep the same sorting
15222  // on all processors
15223  for (std::map<std::pair<double, double>, Node*>::iterator it_map
15224  = sorted_nodes_pt.begin(); it_map != sorted_nodes_pt.end(); it_map++)
15225  {
15226  // Store the pointer to the node
15227  this->Sorted_shared_boundary_node_pt[b][counter++] = (*it_map).second;
15228  }
15229 
15230  } // for (i < nmy_rank_shd_bnd)
15231 
15232  }
15233 
15234  //========================================================================
15235  // Re-establish the shared boundary elements after the adaptation
15236  // process (the updating of shared nodes is optional and performed by
15237  // default)
15238  //========================================================================
15239  template <class ELEMENT>
15242  const bool update_elements,
15243  const bool flush_nodes,
15244  const bool update_nodes)
15245  {
15246  // Get the rank of the current processor
15247  const unsigned my_rank = this->communicator_pt()->my_rank();
15248 
15249  // Go through the boundaries know as shared boundaries and copy the
15250  // elements to the corresponding storage
15251 
15252  // Get the initial shared boundary id
15253  const unsigned initial_id = this->initial_shared_boundary_id();
15254 
15255  // Get the final shared boundary id
15256  const unsigned final_id = this->final_shared_boundary_id();
15257 
15258  if (flush_elements)
15259  {
15260  // Flush the shared boundaries storage for elements
15261  this->flush_shared_boundary_element();
15262  // .. and also flush the face indexes associated with the element
15263  this->flush_face_index_at_shared_boundary();
15264  } // if (flush_elements)
15265 
15266  if (flush_nodes)
15267  {
15268  // Flush the shared boundaries storage for nodes
15269  this->flush_shared_boundary_node();
15270  } // if (flush_nodes)
15271 
15272  for (unsigned b = initial_id; b < final_id; b++)
15273  {
15274  // Check if the boundary is on the current processor
15275  Vector<unsigned> procs_from_shrd_bnd;
15276  procs_from_shrd_bnd = this->shared_boundary_from_processors(b);
15277  bool current_processor_has_b_boundary = false;
15278  const unsigned n_procs_from_shrd_bnd = procs_from_shrd_bnd.size();
15279  for (unsigned p = 0; p < n_procs_from_shrd_bnd; p++)
15280  {
15281  if (procs_from_shrd_bnd[p] == my_rank)
15282  {
15283  current_processor_has_b_boundary = true;
15284  break; // break for (p < n_procs_from_shrd_bnd)
15285  }
15286  } // for (p < n_procs_from_shrd_bnd)
15287 
15288  if (current_processor_has_b_boundary)
15289  {
15290  if (update_elements)
15291  {
15292  const unsigned nboundary_ele = this->nboundary_element(b);
15293  for (unsigned e = 0; e < nboundary_ele; e++)
15294  {
15295  // Get the boundary element and add it to the shared
15296  // boundary elements structure
15297  FiniteElement* bnd_ele_pt = this->boundary_element_pt(b, e);
15298  this->add_shared_boundary_element(b, bnd_ele_pt);
15299  // ... do the same with the face index information
15300  int face_index = this->face_index_at_boundary(b, e);
15301  this->add_face_index_at_shared_boundary(b, face_index);
15302  } // for (e < nboundary_element)
15303  } // if (update_elements)
15304 
15305  if (update_nodes)
15306  {
15307 
15308 
15309  const unsigned nboundary_node = this->nboundary_node(b);
15310  for (unsigned n = 0; n < nboundary_node; n++)
15311  {
15312  Node* bnd_node_pt = this->boundary_node_pt(b, n);
15313  this->add_shared_boundary_node(b, bnd_node_pt);
15314  } // for (n < nboundary_node)
15315  } // if (update_nodes)
15316 
15317  } // if (current_processor_has_b_boundary)
15318  } // for (b < final_id)
15319 
15320  }
15321 
15322  //======================================================================
15323  // Sort the nodes on shared boundaries so that the processors that share
15324  // a boundary agree with the order of the nodes on the boundary
15325  //======================================================================
15326  template <class ELEMENT>
15328  {
15329  // Get the number of processors
15330  unsigned nproc = this->communicator_pt()->nproc();
15331  // Get the rank of the current processor
15332  unsigned my_rank = this->communicator_pt()->my_rank();
15333 
15334  // Get some timings
15335  double tt_start = 0.0;
15336  double tt_end=0.0;
15338  {
15339  tt_start=TimingHelpers::timer();
15340  }
15341 
15342  // -------------------------------------------------------------------
15343  // BEGIN: Get the node names and the shared nodes
15344  // -------------------------------------------------------------------
15345 
15346  // Container where to store the nodes on shared boundaries no
15347  // associated with the processor that receives the elements/nodes
15348  // other_proc_shd_bnd_node_pt[iproc][jproc][shd_bnd_id][index]
15350  other_proc_shd_bnd_node_pt(nproc);
15351  // Resize the container
15352  for (unsigned iproc = 0; iproc < nproc; iproc++)
15353  {
15354  // Resize the container
15355  other_proc_shd_bnd_node_pt[iproc].resize(nproc);
15356  for (unsigned jproc = 0; jproc < nproc; jproc++)
15357  {
15358  // Get the number of shared boundaries
15359  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
15360  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
15361  const unsigned nshared_bound = final_shd_bnd_id - initial_shd_bnd_id;
15362  other_proc_shd_bnd_node_pt[iproc][jproc].resize(nshared_bound);
15363  } // for (jproc < nproc)
15364 
15365  } // for (iproc < nproc)
15366 
15367  // Store the global node names
15368  // global_node_name[x][ ][ ] Global node number
15369  // global_node_name[ ][x][ ] Global node names
15370  // global_node_name[ ][ ][x] Global node info.
15371  Vector<Vector<Vector<unsigned> > > global_node_names;
15372 
15373  // Creates a map between the node name and the index of the global
15374  // node so we can access all its node names
15375  std::map<Vector<unsigned>, unsigned> node_name_to_global_index;
15376 
15377  // Store the global shared nodes pointers
15378  Vector<Node*> global_shared_node_pt;
15379 
15380  // Get the time for computation of global nodes names and shared
15381  // nodes
15382  double t_start_global_node_names_and_shared_nodes =
15384 
15385  // Compute all the names of the nodes and fill in the
15386  // "other_proc_shd_bnd_node_pt" structure with the nodes that live
15387  // on this processor (my_rank) by looking over all their names
15388  compute_global_node_names_and_shared_nodes(other_proc_shd_bnd_node_pt,
15389  global_node_names,
15390  node_name_to_global_index,
15391  global_shared_node_pt);
15392 
15393  // Compute the number of elements before adding new ones
15394  const unsigned n_ele = this->nelement();
15395 
15396  if (Print_timings_level_adaptation>1)
15397  {
15398  // The total time for computation of global nodes names and
15399  // shared nodes
15400  double t_final_global_node_names_and_shared_nodes =
15401  TimingHelpers::timer() - t_start_global_node_names_and_shared_nodes;
15402  oomph_info << "CPU for computing global node names and shared nodes "
15403  << "[n_ele="<< n_ele << "]: "
15404  << t_final_global_node_names_and_shared_nodes << std::endl;
15405  }
15406 
15407  // -------------------------------------------------------------------
15408  // END: Get the node names and the shared nodes
15409  // -------------------------------------------------------------------
15410 
15411  // -------------------------------------------------------------------
15412  // BEGIN: Using the global node names each processor sends info. of
15413  // the nodes shared with other processors regarding whether they are
15414  // on an original boundary or not. This is required so that at the
15415  // re-generation of halo(ed) elements stage they have the updated
15416  // information
15417  // -------------------------------------------------------------------
15418 
15419  // Get the time for sending info. of shared nodes on original
15420  // boundaries
15421  double t_start_send_info_shd_nodes_on_original_bnds =
15423 
15424  // Send the boundary node info. of nodes on shared boundaries across
15425  // processors
15426  send_boundary_node_info_of_shared_nodes(global_node_names,
15427  node_name_to_global_index,
15428  global_shared_node_pt);
15429 
15430  if (Print_timings_level_adaptation>1)
15431  {
15432  // The total time for sending info. of shared nodes lying on
15433  // original boundaries
15434  oomph_info
15435  <<"CPU for sending info. of shared nodes on original boundaries: "
15436  <<TimingHelpers::timer()-t_start_send_info_shd_nodes_on_original_bnds
15437  <<std::endl;
15438  }
15439 
15440  // -------------------------------------------------------------------
15441  // END: Using the global node names each processor sends info. of
15442  // the nodes shared with other processors regarding whether they are
15443  // on an original boundary or not. This is required so that at the
15444  // re-generation of halo(ed) elements stage they have the updated
15445  // information
15446  // -------------------------------------------------------------------
15447 
15448  // -------------------------------------------------------------------
15449  // BEGIN: Identify the elements of the mesh that have nodes on the
15450  // shared boundaries
15451  // -------------------------------------------------------------------
15452 
15453  // Store the elements that have a node on a shared boundary with
15454  // other processors
15455  // ele_with_node_on_shd_bnd_pt[x][ ][ ]: iproc
15456  // ele_with_node_on_shd_bnd_pt[ ][x][ ]: ishd boundary with iproc
15457  // ele_with_node_on_shd_bnd_pt[ ][ ][x]: element with node on shared
15458  // boundary with iproc
15459  Vector<Vector<Vector<FiniteElement*> > > ele_with_node_on_shd_bnd_pt(nproc);
15460  // Resize the container with the number of shared boundaries within
15461  // each processor
15462 
15463  // loop over the processors
15464  for (unsigned iproc = 0; iproc < nproc; iproc++)
15465  {
15466  const unsigned n_shd_bnd_iproc = this->nshared_boundaries(my_rank, iproc);
15467  ele_with_node_on_shd_bnd_pt[iproc].resize(n_shd_bnd_iproc);
15468  } // for (iproc < nproc)
15469 
15470  // Go through all the elements and check whether any of their nodes
15471  // lies on any of the shared boundaries
15472 
15473  // loop over the elements
15474  for (unsigned e = 0; e < n_ele; e++)
15475  {
15476  // Get the element
15477  FiniteElement* ele_pt = this->finite_element_pt(e);
15478  // Get the number of nodes
15479  const unsigned n_nodes = ele_pt->nnode();
15480  // loop over the nodes and check whether any of them lies on a
15481  // shared boundary
15482  for (unsigned n = 0; n < n_nodes; n++)
15483  {
15484  // Get the node
15485  Node* node_pt = ele_pt->node_pt(n);
15486 
15487  // Now check whether the current node lies on a shared boundary
15488  // within any other processor
15489 
15490  // loop over the processors
15491  for (unsigned iproc = 0; iproc < nproc; iproc++)
15492  {
15493  // The number of boundaries shared with the current processor
15494  // (if iproc==my_rank then there are no shared boundaries
15495  // between them)
15496  const unsigned n_shd_bnd_iproc =
15497  this->nshared_boundaries(my_rank, iproc);
15498 
15499  // There are no info. with myself
15500  if (iproc != my_rank && n_shd_bnd_iproc > 0)
15501  {
15502  // Get the boundaries ids of the shared boundaries with
15503  // iproc processor
15504  Vector<unsigned> shd_bnd_ids =
15505  this->shared_boundaries_ids(my_rank, iproc);
15506 
15507  // Loop over shd bnds with processor "iproc"
15508  for (unsigned isb = 0; isb < n_shd_bnd_iproc; isb++)
15509  {
15510  const unsigned shd_bnd_id = shd_bnd_ids[isb];
15511  const unsigned n_ele_shd_bnd =
15512  this->nshared_boundary_element(shd_bnd_id);
15513 
15514  // Check if the node is on this boundary only if there are
15515  // elements on it
15516  if (n_ele_shd_bnd > 0 &&
15517  this->is_node_on_shared_boundary(shd_bnd_id, node_pt))
15518  {
15519  // Add the element into those that have a
15520  // node on the current shared boundary
15521  ele_with_node_on_shd_bnd_pt[iproc][isb].push_back(ele_pt);
15522 
15523  } // Are there elements on the boundary and the node lies
15524  // on this boundary
15525 
15526  } // for (isb < n_shd_bnd_iproc)
15527 
15528  } // if (iproc != my_rank && n_shd_bnd_iproc > 0)
15529 
15530  } // for (iproc < nproc)
15531 
15532  } // for (n < n_nodes)
15533 
15534  } // for (e < n_ele)
15535 
15536  // -------------------------------------------------------------------
15537  // END: Identify the elements of the mesh that have nodes on the
15538  // shared boundaries
15539  // -------------------------------------------------------------------
15540 
15541  // -------------------------------------------------------------------
15542  // BEGIN: Create the halo(ed) elements. Loop over the processors and
15543  // the shared boundaries within each processor. Get the elements on
15544  // the shared boundaries, mark them as haloed in this processor and
15545  // as halo on the element that will receive the info.
15546  // -------------------------------------------------------------------
15547 
15548  // ********************************************************************
15549  // General strategy:
15550  // 1) Go through all the elements on the shared boundaries, mark these
15551  // elements as haloed, same as their nodes.
15552  // 2) Package the info. of the nodes and the elements.
15553  // 3) Send and receive the info across processors
15554  // 4) Unpackage it and create halo elements and nodes as indicated by
15555  // the received info.
15556  // ********************************************************************
15557 
15558  // Keep track of the currently created nodes within each
15559  // processor. We need to keep track of these nodes so they can be
15560  // referred at a second stage.
15561  Vector<Vector<Node*> > iproc_currently_created_nodes_pt(nproc);
15562 
15563  // Get the time to re-generate halo(ed) elements/nodes (first stage)
15564  double t_start_regenerate_halo_ed_elements_nodes_first_stage =
15566 
15567  // Go through all processors
15568  for (unsigned iproc = 0; iproc < nproc; iproc++)
15569  {
15570  // Send and receive info. to/from other processors
15571  if (iproc != my_rank)
15572  {
15573  // Get the number of boundaries shared with the send proc (iproc)
15574  const unsigned nshared_boundaries_with_iproc =
15575  this->nshared_boundaries(my_rank, iproc);
15576 
15577  if (nshared_boundaries_with_iproc > 0)
15578  {
15579  // ******************************************************************
15580  // Stage 1
15581  // ******************************************************************
15582  // Step (1) Mark the elements adjacent to the shared boundaries as
15583  // haloed, mark the nodes on these elements as haloed nodes
15584  // Step (2) Create packages of information indicating the generation
15585  // of halo elements and nodes
15586  // ******************************************************************
15587 
15588  // Clean send and receive buffers
15589  Flat_packed_unsigneds.clear();
15590  Flat_packed_doubles.clear();
15591 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15593 #endif
15594 
15595  // Get the boundaries ids shared with "iproc"
15596  Vector<unsigned> bound_shared_with_iproc;
15597  bound_shared_with_iproc = this->shared_boundaries_ids(my_rank, iproc);
15598 
15599  // Loop over shared boundaries with processor "iproc"
15600  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
15601  {
15602  const unsigned bnd_id = bound_shared_with_iproc[bs];
15603 // DEBP(bnd_id);
15604  const unsigned nel_bnd = this->nshared_boundary_element(bnd_id);
15605 // DEBP(nel_bnd);
15606 
15607  // Container to store the elements marked as haloed
15608  Vector<FiniteElement*> haloed_element;
15609 
15610  // All the elements adjacent to the boundary should be
15611  // marked as haloed elements
15612  if (nel_bnd > 0)
15613  {
15614  // Map to know which element have been already added
15615  std::map<FiniteElement*,bool> already_added;
15616 
15617  // Loop over the elements adjacent to boundary "bnd_id"
15618  for (unsigned e = 0; e < nel_bnd; e++)
15619  {
15620  // Get pointer to the element adjacent to boundary bnd_id
15621  FiniteElement* ele_pt =
15622  this->shared_boundary_element_pt(bnd_id, e);
15623 
15624  // Check if the element has been already added. Elemets
15625  // are repeated if they have two faces on the shared
15626  // boundary
15627  if (!already_added[ele_pt])
15628  {
15629  // Add the element to the container of haloed elements
15630  haloed_element.push_back(ele_pt);
15631  // Mark the element as already added
15632  already_added[ele_pt] = true;
15633  }
15634 
15635  } // for (e < nel_bnd)
15636 
15637  // In addition to the elements on the boundary we also
15638  // need to mark (as haloed) any element on the mesh with a
15639  // node on the shared boundary
15640 
15641  // Get the number of elements with a node on the current
15642  // shared boundary
15643  const unsigned n_ele_with_node_on_shd_bnd =
15644  ele_with_node_on_shd_bnd_pt[iproc][bs].size();
15645  // loop and add the elements that have a node on the
15646  // current shared boundary with the current processor
15647  for (unsigned iele = 0; iele < n_ele_with_node_on_shd_bnd; iele++)
15648  {
15649  // Get the element
15650  FiniteElement* ele_pt =
15651  ele_with_node_on_shd_bnd_pt[iproc][bs][iele];
15652  // Check if it has not been already added
15653  if (!already_added[ele_pt])
15654  {
15655  // Add it!!
15656  haloed_element.push_back(ele_pt);
15657  // Mark it as done
15658  already_added[ele_pt] = true;
15659  } // if (!already_added[ele_pt])
15660 
15661  } // for (iele < n_ele_with_node_on_shd_bnd)
15662 
15663  } // if (nel_bnd > 0)
15664 
15665  // Get the total number of haloed elements
15666  const unsigned nhaloed_ele = haloed_element.size();
15667  // DEBP(nhaloed_ele);
15668  // DEBP(my_rank);
15669  // DEBP(iproc);
15670  // The very first data of the flat packed is the number of haloed
15671  // elements, this will be the number of halo element to create on
15672  // the receiver processor
15673  Flat_packed_unsigneds.push_back(nhaloed_ele);
15674 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15675  std::stringstream junk;
15676  junk << "Number of haloed elements " << nhaloed_ele;
15677  Flat_packed_unsigneds_string.push_back(junk.str());
15678 #endif
15679 
15680  // Loop over the marked haloed elements
15681  for (unsigned e = 0; e < nhaloed_ele; e++)
15682  {
15683  // Get pointer to the marked haloed element
15684  FiniteElement* ele_pt = haloed_element[e];
15685  const unsigned nroot_haloed_ele =
15686  this->nroot_haloed_element(iproc);
15687 
15688  // Check if the element has been already added to the
15689  // halo(ed) scheme
15690  GeneralisedElement *gen_ele_pt = ele_pt;
15691  const unsigned haloed_ele_index =
15692  this->try_to_add_root_haloed_element_pt(iproc, gen_ele_pt);
15693 
15694  // Was the element added or only returned the index of the
15695  // element
15696  if (nroot_haloed_ele == haloed_ele_index)
15697  {
15698  Flat_packed_unsigneds.push_back(1);
15699 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15700  Flat_packed_unsigneds_string.push_back("Haloed element needs to be constructed");
15701 #endif
15702 
15703  // Get additional info. related with the haloed element
15704  get_required_elemental_information_helper(iproc, ele_pt);
15705 
15706  // Get the nodes on the element
15707  const unsigned nnodes = ele_pt->nnode();
15708  for (unsigned j = 0; j < nnodes; j++)
15709  {
15710  Node* node_pt = ele_pt->node_pt(j);
15711 
15712  // Package the info. of the nodes
15713  // The destination processor goes in the arguments
15714  add_haloed_node_helper(iproc, node_pt);
15715 
15716  } // for (j < nnodes)
15717  } // add the element and send its nodes
15718  else // The haloed element already exists
15719  {
15720  Flat_packed_unsigneds.push_back(0);
15721 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15722  Flat_packed_unsigneds_string.push_back("Haloed element already exists");
15723 #endif
15724  Flat_packed_unsigneds.push_back(haloed_ele_index);
15725 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15726  Flat_packed_unsigneds_string.push_back("Index of existing haloed element");
15727 #endif
15728  } // else (next_haloed_ele == external_haloed_ele_index)
15729  } // for (e < nel_bnd)
15730 
15731  } // for (bs < nshared_boundaries_with_iproc)
15732 
15733  // *******************************************************************
15734  // Stage (2)
15735  // *******************************************************************
15736  // Step (1) Send and receive the data to create halo elements and
15737  // nodes
15738  // *******************************************************************
15739  // The processor to which send the elements
15740  int send_proc = static_cast<int>(iproc);
15741  // The processor from which receive the elements
15742  int recv_proc = static_cast<int>(iproc);
15743  send_and_receive_elements_nodes_info(send_proc, recv_proc);
15744 
15745  // *******************************************************************
15746  // Stage (3)
15747  // *******************************************************************
15748  // Step (1) Unpackage the info and create the halo elements and nodes
15749  // *******************************************************************
15750 
15751  // Reset the counters
15754 
15755  // Loop over shared boundaries with processor "iproc"
15756  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
15757  {
15758  // Get the number of halo element to be created
15759  const unsigned nhaloed_ele =
15761 
15762 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15764  << " Number of elements need to be constructed "
15766  << std::endl;
15767 #endif
15768 
15769  // Loop over boundaries shared with processor "urecv_proc"
15770  for (unsigned e = 0; e < nhaloed_ele; e++)
15771  {
15772  // Create halo element from received info. of "iproc"
15773  // processor on the current processor
15774  create_halo_element(iproc,
15775  iproc_currently_created_nodes_pt[iproc],
15776  other_proc_shd_bnd_node_pt,
15777  global_node_names,
15778  node_name_to_global_index,
15779  global_shared_node_pt);
15780 
15781  } // for (e < nhaloed_ele)
15782 
15783  } // for (bs < nshared_boundaries_with_iproc)
15784 
15785  } // if (nshared_bound_recv_proc > 0)
15786 
15787  } // if (iproc != my_rank)
15788 
15789  } // for (iproc < nproc) (general loop to send and receive info.)
15790 
15791  if (Print_timings_level_adaptation>1)
15792  {
15793  // Get the time to re-generate halo(ed) elements/nodes (first stage)
15794  double t_final_regenerate_halo_ed_elements_nodes_first_stage =
15795  TimingHelpers::timer() - t_start_regenerate_halo_ed_elements_nodes_first_stage;
15796 
15797  oomph_info << "CPU for re-generating halo(ed) elements/nodes "
15798  << "(first stage) [n_ele="<< n_ele << "]: "
15799  << t_final_regenerate_halo_ed_elements_nodes_first_stage
15800  << std::endl;
15801  }
15802 
15803  // -------------------------------------------------------------------
15804  // END: Create the halo(ed) elements. Loop over the processors and
15805  // the shared boundaries within each processor. Get the elements on
15806  // the shared boundaries, mark them as haloed in this processor and
15807  // as halo on the element that will receive the info.
15808  // -------------------------------------------------------------------
15809 
15810  // -------------------------------------------------------------------
15811  // BEGIN: Create any additional haloed element, those that dont lie
15812  // on a shared boundary but that shared a node with other processor
15813  // -------------------------------------------------------------------
15814 
15815  // Get the time to re-generate halo(ed) elements/nodes (second stage)
15816  double t_start_regenerate_halo_ed_elements_nodes_second_stage =
15818 
15819  // Create any additional halo(ed) elements between processors that
15820  // have no shared boundaries but that have shared nodes
15821  reset_halo_haloed_scheme_helper(other_proc_shd_bnd_node_pt,
15822  iproc_currently_created_nodes_pt,
15823  global_node_names,
15824  node_name_to_global_index,
15825  global_shared_node_pt);
15826 
15827  if (Print_timings_level_adaptation>1)
15828  {
15829  // Get the time to re-generate halo(ed) elements/nodes (second stage)
15830  double t_final_regenerate_halo_ed_elements_nodes_second_stage =
15831  TimingHelpers::timer() - t_start_regenerate_halo_ed_elements_nodes_second_stage;
15832 
15833  oomph_info << "CPU for re-generating halo(ed) elements/nodes "
15834  << "(second stage) [n_ele="<< n_ele << "]: "
15835  << t_final_regenerate_halo_ed_elements_nodes_second_stage
15836  << std::endl;
15837  }
15838 
15839  // -------------------------------------------------------------------
15840  // END: Create any additional haloed element, those that dont lie on
15841  // a shared boundary but that shared a node with other processor
15842  // -------------------------------------------------------------------
15843 
15844  // Clean send and receive buffers
15845  Flat_packed_unsigneds.clear();
15846  Flat_packed_doubles.clear();
15847 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15849 #endif
15850 
15851  // Document the timings for reseting halo and haloed scheme (without
15852  // classification of halo and haloed nodes)
15853  if (Print_timings_level_adaptation>1)
15854  {
15855  tt_end = TimingHelpers::timer();
15856  oomph_info
15857  << "CPU for resetting halo-haloed scheme (without classification of halo and haloed nodes): "
15858  << tt_end-tt_start << std::endl;
15859  }
15860 
15861  // ------------------------------------------------------------------
15862  // BEGIN: Classify halo(ed) elements and nodes
15863  // ------------------------------------------------------------------
15864  const bool report_stats = true;
15865  DocInfo tmp_doc_info;
15866  tmp_doc_info.disable_doc();
15867 
15868  // Classify nodes
15869  this->classify_halo_and_haloed_nodes(tmp_doc_info,report_stats);
15870 
15871  // Document the timings for reseting halo and haloed scheme (with
15872  // classification of halo and haloed nodes)
15873  if (Print_timings_level_adaptation>1)
15874  {
15875  tt_end = TimingHelpers::timer();
15876  oomph_info
15877  << "CPU for resetting halo-haloed scheme (with classification of halo and haloed nodes): "
15878  << tt_end-tt_start << std::endl;
15879  }
15880 
15881  // ------------------------------------------------------------------
15882  // END: Classify halo(ed) elements and nodes
15883  // ------------------------------------------------------------------
15884 
15885  }
15886 
15887 //======================================================================
15888 // \short Compute the alias of the nodes on shared boundaries in this
15889 // (my_rank) processor with other processors. Also compute the alias
15890 // of nodes on shared boundaries of other processors with other
15891 // processors (useful when there is an element that requires to be
15892 // sent to this (my_rank) processor because there is a shared node
15893 // between this (my_rank) and other processors BUT there is not a
15894 // shared boundary between this and the other processor
15895 // ======================================================================
15896 template <class ELEMENT>
15899  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
15900  &other_proc_shd_bnd_node_pt,
15901  Vector<Vector<Vector<unsigned> > > &global_node_names,
15902  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
15903  Vector<Node*> &global_shared_node_pt)
15904 {
15905  // Get the number of processors
15906  const unsigned nproc = this->communicator_pt()->nproc();
15907  // Get the rank of the current processor
15908  const unsigned my_rank = this->communicator_pt()->my_rank();
15909  // Get the communicator of the mesh
15910  OomphCommunicator* comm_pt = this->communicator_pt();
15911 
15912  // ---------------------------------------------------------------
15913  // BEGIN: Get the elements adjacent to shared boundaries and give
15914  // a unique node number to the nodes on the shared boundaries in
15915  // this processor
15916  // ---------------------------------------------------------------
15917 
15918  // Counter for the nodes on shared boundaries in this (my_rank)
15919  // processor
15920  unsigned counter_nodes = 0;
15921  // Keep track of visited nodes
15922  std::map<Node*, bool> done_node;
15923  // ... and its local node number
15924  std::map<Node*, unsigned> local_node_number;
15925  // ... and the inverted relation from local node number to node_pt
15926  Vector<Node*> local_node_pt;
15927 
15928  // Stores the j-th node name associated with the i-th local node
15929  // on shared boundaries in this processor (my_rank)
15930  // local_node_names[i][j][0] = my_rank (this processor)
15931  // local_node_names[i][j][1] = iproc (the processor with which there
15932  // is a shared boundary)
15933  // local_node_names[i][j][2] = the shared boundary id between this
15934  // (my_rank) processor and iproc
15935  // processor
15936  // local_node_names[i][j][3] = the node index on the shared boundary
15937  // local_node_names[i][j][4] = the local node index (i). This may
15938  // be unnecessary since we alread know the
15939  // index but we also send this info. to
15940  // the root processor that is why we store
15941  // them here
15942  Vector<Vector<Vector<unsigned> > > local_node_names;
15943 
15944  // loop over the processors
15945  for (unsigned iproc = 0; iproc < nproc; iproc++)
15946  {
15947  // There are not shared boundaries with myself
15948  if (iproc != my_rank)
15949  {
15950  // Get the number of shared boundaries with iproc
15951  const unsigned n_shd_bnds_with_iproc =
15952  this->nshared_boundaries(my_rank, iproc);
15953 
15954  // Get the boundaries ids shared with iproc
15955  Vector<unsigned> bnd_shd_with_iproc =
15956  this->shared_boundaries_ids(my_rank, iproc);
15957 
15958  // Loop over the shared boundaries with processor iproc
15959  for (unsigned ishd = 0; ishd < n_shd_bnds_with_iproc; ishd++)
15960  {
15961  // Keep track of visited nodes with this shared boundary
15962  std::map<Node*,bool> done_node_shd_bnd;
15963  // The boundary id
15964  unsigned shd_bnd_id = bnd_shd_with_iproc[ishd];
15965  // Get the number of element on the shared boundary
15966  const unsigned n_shd_bnd_ele =
15967  this->nshared_boundary_element(shd_bnd_id);
15968 
15969  // loop over the elements adjacent to the shared boundary
15970  for (unsigned e = 0; e < n_shd_bnd_ele; e++)
15971  {
15972  // Get the element
15973  FiniteElement* ele_pt =
15974  this->shared_boundary_element_pt(shd_bnd_id, e);
15975 
15976  // Get the number of nodes on the element
15977  const unsigned n_nodes = ele_pt->nnode();
15978 
15979  // loop over the nodes of the current element
15980  for (unsigned n = 0; n < n_nodes; n++)
15981  {
15982  // Get the node
15983  Node* node_pt = ele_pt->node_pt(n);
15984 
15985  // Has the node been visited with this shared boundary?
15986  // And, is this a node on the shd_bnd_id shared boundary
15987  // with processor iproc?
15988  if (!done_node_shd_bnd[node_pt] &&
15989  this->is_node_on_shared_boundary(shd_bnd_id,
15990  node_pt))
15991  {
15992  // Mark the done as done with this shared boundary
15993  done_node_shd_bnd[node_pt] = true;
15994 
15995  // Get the index of the node on the shared boundary
15996  // -------------------------------------------------
15997  // Get the number of nodes on the shared boundary
15998  const unsigned n_nodes_shd_bnd =
15999  nsorted_shared_boundary_node(shd_bnd_id);
16000 
16001  // The index
16002  unsigned index = 0;
16003 
16004 #ifdef PARANOID
16005  // Flag to know if the node has been found
16006  bool found_node_on_shared_boundary = false;
16007 #endif
16008  // Loop over the nodes on the shared boundary to find
16009  // the node
16010  for (unsigned k = 0; k < n_nodes_shd_bnd; k++)
16011  {
16012  // Get the k-th node on the shared boundary
16013  Node* shd_bnd_node_pt =
16014  sorted_shared_boundary_node_pt(shd_bnd_id, k);
16015 
16016  // Is the same node?
16017  if (shd_bnd_node_pt == node_pt)
16018  {
16019  // This is the index
16020  index = k;
16021 #ifdef PARANOID
16022  // Mark as found
16023  found_node_on_shared_boundary = true;
16024 #endif
16025  break; // break
16026 
16027  } // if (shd_bnd_node_pt == node_pt)
16028 
16029  } // for (k < n_nodes_shd_bnd)
16030 
16031 #ifdef PARANOID
16032  if (!found_node_on_shared_boundary)
16033  {
16034  std::ostringstream error_message;
16035  error_message
16036  <<"The index of the node on boundary ("<<shd_bnd_id
16037  <<") was not found.\n"
16038  <<"These are the node coordinates\n"
16039  <<"("<<node_pt->x(0)<<","<<node_pt->x(1)<<").\n";
16040  throw OomphLibError(error_message.str(),
16041  OOMPH_CURRENT_FUNCTION,
16042  OOMPH_EXCEPTION_LOCATION);
16043  }
16044 #endif
16045 
16046  // Create the node name
16047  Vector<unsigned> node_name(5);
16048  node_name[0] = my_rank;
16049  node_name[1] = iproc;
16050  node_name[2] = shd_bnd_id;
16051  node_name[3] = index;
16052  // The node number is filled in the following if/else
16053  //node_name[4] = ?;
16054 
16055  // Has the node already been visited?
16056  if (!done_node[node_pt])
16057  {
16058  // If not ...
16059 
16060  // Add the node to the local nodes
16061  local_node_pt.push_back(node_pt);
16062 
16063  // Assign a local node number to the node
16064  local_node_number[node_pt] = counter_nodes;
16065  // Store the local node number
16066  node_name[4] = counter_nodes;
16067  // Increase the counter of nodes
16068  counter_nodes++;
16069  // ... and mark it as visited
16070  done_node[node_pt] = true;
16071 
16072  // Push back the node name (the first
16073  // one found for this node)
16074  Vector<Vector<unsigned> > first_node_name(1);
16075  first_node_name[0] = node_name;
16076  local_node_names.push_back(first_node_name);
16077  }
16078  else
16079  {
16080  // If yes ...
16081 
16082  // Get the local node number
16083  unsigned node_number = local_node_number[node_pt];
16084 
16085  // Store the local node number
16086  node_name[4] = node_number;
16087 
16088  // Push back the node name for the
16089  // node number
16090  local_node_names[node_number].push_back(node_name);
16091 
16092  }
16093 
16094  } // Is on shared boundary?
16095 
16096  } // for (n < nnodes)
16097 
16098  } // for (e < n_shd_bnd_ele)
16099 
16100  } // for (ishd < n_shd_bnds_with_iproc)
16101 
16102  } // if (iproc != my_rank)
16103 
16104  } // for (iproc < nproc)
16105 
16106  // ---------------------------------------------------------------
16107  // END: Get the elements adjacent to shared boundaries and give
16108  // a unique node number to the nodes on the shared boundaries in
16109  // this processor
16110  // ---------------------------------------------------------------
16111 
16112  // ---------------------------------------------------------------
16113  // BEGIN: Package the names of the local nodes
16114  // ---------------------------------------------------------------
16115  // Counter for the number of names of the nodes
16116  unsigned n_total_local_names = 0;
16117  // Get the number of local nodes
16118  const unsigned n_local_nodes = local_node_names.size();
16119  // loop over the number of local nodes and get the number of names
16120  // of each node
16121  for (unsigned i = 0; i < n_local_nodes; i++)
16122  {
16123  // Get the number of names of the i-th local node
16124  const unsigned n_inode_names = local_node_names[i].size();
16125  // ... and add them to the total number of local names
16126  n_total_local_names+=n_inode_names;
16127  } // for (i < n_local_nodes)
16128 
16129  // We store five data per node name (my_rank,iproc,shd_bnd_id,idx,node#)
16130  // where node# is the node number on this processor (my_rank)
16131  const unsigned n_info_per_node_name = 5;
16132  // Storage for the flat package
16133  Vector<unsigned> flat_packed_send_udata(n_total_local_names*n_info_per_node_name);
16134  // A counter
16135  unsigned counter = 0;
16136  // loop over the local nodes
16137  for (unsigned i = 0; i < n_local_nodes; i++)
16138  {
16139  // Get the number of names of the i-th local node
16140  const unsigned n_inode_names = local_node_names[i].size();
16141  // loop over the names of the i-th local node
16142  for (unsigned j = 0 ; j < n_inode_names; j++)
16143  {
16144  // Store this processor id (my_rank)
16145  flat_packed_send_udata[counter++]=local_node_names[i][j][0];
16146  // Store the processor with which the shared boundary exist
16147  flat_packed_send_udata[counter++]=local_node_names[i][j][1];
16148  // Store the shared boundary id
16149  flat_packed_send_udata[counter++]=local_node_names[i][j][2];
16150  // Store the index of the node on the shared boundary
16151  flat_packed_send_udata[counter++]=local_node_names[i][j][3];
16152  // Store the local node number on this processor (my_rank)
16153  flat_packed_send_udata[counter++]=local_node_names[i][j][4];
16154  } // for (j < n_inode_names)
16155 
16156  } // for (i < n_local_nodes)
16157 
16158  // Reset the counter
16159  counter = 0;
16160 
16161  // The number of data that will be sent to root from this
16162  // (my_rank) processor
16163  const unsigned n_udata_send_to_root = flat_packed_send_udata.size();
16164 
16165  // ---------------------------------------------------------------
16166  // END: Package the names of the local nodes
16167  // ---------------------------------------------------------------
16168  // ---------------------------------------------------------------
16169  // BEGIN: Send the data to the root processor
16170  // ---------------------------------------------------------------
16171 
16172  // The root processor is in charge of computing all the node names
16173  // of the nodes on the shared boundaries
16174 
16175  // Choose the root processor
16176  const unsigned root_processor = 0;
16177 
16178  // The vector where the root processor receives how many names
16179  // will receive from the other processors
16180  Vector<unsigned> root_n_names_per_processor(nproc);
16181 
16182  // Send the number of names that the root processor will receive
16183  // from each processor
16184  MPI_Gather(&n_total_local_names, 1, MPI_UNSIGNED,
16185  &root_n_names_per_processor[0], 1, MPI_UNSIGNED,
16186  root_processor, comm_pt->mpi_comm());
16187 
16188  // Get the total number of data to receive from all processor in
16189  // root
16190  unsigned root_n_total_udata_receive = 0;
16191  Vector<int> root_n_udata_to_receive(nproc,0);
16192  for (unsigned iproc = 0; iproc < nproc; iproc++)
16193  {
16194  root_n_udata_to_receive[iproc]=
16195  root_n_names_per_processor[iproc]*n_info_per_node_name;
16196  root_n_total_udata_receive+=root_n_udata_to_receive[iproc];
16197  }
16198 
16199  // Stores and compute the offsets (in root) for the data received
16200  // from each processor
16201  Vector<int> root_uoffsets_receive(nproc,0);
16202  root_uoffsets_receive[0] = 0;
16203  for (unsigned iproc = 1; iproc < nproc; iproc++)
16204  {
16205  // Compute the offset to obtain the data from each processor
16206  root_uoffsets_receive[iproc] =
16207  root_uoffsets_receive[iproc-1] + root_n_udata_to_receive[iproc-1];
16208 
16209  }
16210 
16211  // Create at least one entry so we don't get a seg fault below
16212  if (flat_packed_send_udata.size()==0)
16213  {
16214  flat_packed_send_udata.resize(1);
16215  }
16216 
16217  // Vector where to receive the info on root from all processors
16218  Vector<unsigned> root_flat_packed_receive_udata(root_n_total_udata_receive);
16219  // Only root receive data, the others dont, then resize the
16220  // container to have at least one entry
16221  if (my_rank!=root_processor)
16222  {
16223  // Create at least one entry so we don't get a seg fault below
16224  if (root_flat_packed_receive_udata.size()==0)
16225  {
16226  root_flat_packed_receive_udata.resize(1);
16227  }
16228  } // if (my_rank!=root_processor)
16229 
16230  // Send the info. to the root processor
16231  MPI_Gatherv(&flat_packed_send_udata[0], // Flat package to send
16232  // info. from each
16233  // processor
16234  n_udata_send_to_root, // Total number of data send
16235  // from each processor to root
16236  MPI_UNSIGNED,
16237  &root_flat_packed_receive_udata[0], // Container where
16238  // to receive the
16239  // info. from all
16240  // processors
16241  &root_n_udata_to_receive[0], // Number of data to
16242  // receive from each
16243  // processor
16244  &root_uoffsets_receive[0], // The offset to store the
16245  // info. from each
16246  // processor
16247  MPI_UNSIGNED,
16248  root_processor, //The processor that receives all the
16249  //info.
16250  comm_pt->mpi_comm());
16251 
16252  // Clear and resize the flat package to send
16253  flat_packed_send_udata.clear();
16254  flat_packed_send_udata.resize(0);
16255  // ---------------------------------------------------------------
16256  // END: Send the data to the root processor
16257  // ---------------------------------------------------------------
16258 
16259  // Container where root stores the info. that will be sent to all
16260  // processors. This includes the number of global nodes, the
16261  // number of names for each global node and the names
16262  Vector<unsigned> flat_packed_root_send_receive_udata;
16263 
16264  // ---------------------------------------------------------------
16265  // BEGIN: Unpackage the info. received on root. Compute the alias
16266  // of the nodes
16267  // ---------------------------------------------------------------
16268  if (my_rank == root_processor)
16269  {
16270  // Compute all the names of a node
16271  // root_global_node_name[x][ ][ ] Global node number
16272  // root_global_node_name[ ][x][ ] Global node names
16273  // root_global_node_name[ ][ ][x] Global node info.
16274  Vector<Vector<Vector<unsigned> > > root_global_node_names;
16275 
16276  // Store the info. extracted from the flat package sent to
16277  // root
16278  // root_local_node_names[x][ ] Node name
16279  // root_local_node_names[ ][x] Node info
16280  Vector<Vector<unsigned> > root_local_node_names;
16281 
16282  // Extract all the node names
16283  unsigned rcounter = 0;
16284  // loop over the processors
16285  for (unsigned iproc = 0; iproc < nproc; iproc++)
16286  {
16287  // Get the number of node names received from iproc
16288  const unsigned n_local_names_iproc =
16289  root_n_names_per_processor[iproc];
16290  for (unsigned i = 0; i < n_local_names_iproc; i++)
16291  {
16292  // Get the i-thnode name from iproc
16293  Vector<unsigned> node_name(n_info_per_node_name);
16294  for (unsigned j = 0; j < n_info_per_node_name; j++)
16295  {node_name[j] = root_flat_packed_receive_udata[rcounter++];}
16296 
16297  // Add the i-th node name
16298  root_local_node_names.push_back(node_name);
16299 
16300  } // for (i < n_local_names_iproc)
16301 
16302  } // for (iproc < nproc)
16303 
16304  // Get the number of node names received
16305  const unsigned n_root_local_node_names =
16306  root_local_node_names.size();
16307 
16308  // For each name of the node identify the position of its
16309  // counter-part
16310 
16311  // Given a node name on the iproc,
16312  // (iproc, jproc, ishd_bnd, idx, local_node_number1)
16313  // its counter part must live in jproc, so we look for the
16314  // node name
16315  // (jproc, iproc, ishd_bnd, idx, local_node_number2)
16316 
16317  // Store the index of the node name counter-part
16318  Vector<unsigned> node_name_counter_part(n_root_local_node_names);
16319 
16320  // Keep track of the names of nodes already done
16321  std::map<Vector<unsigned>, bool> done_name;
16322 
16323  // loop over the names of the nodes received from all
16324  // processors
16325  for (unsigned i = 0; i < n_root_local_node_names; i++)
16326  {
16327  // Get the i-th node name
16328  Vector<unsigned> node_name = root_local_node_names[i];
16329 
16330  // Check if this name node has been already done
16331  if (!done_name[node_name])
16332  {
16333  // Mark it as done
16334  done_name[node_name] = true;
16335 #ifdef PARANOID
16336  // Flag to indicate the counter-part name node was
16337  // found
16338  bool found_both_names_node = false;
16339 #endif
16340  // Find the counter-part name node (start from j+1
16341  // since all previous have been found, otherwise we
16342  // would not be here)
16343  for (unsigned j = i+1; j < n_root_local_node_names; j++)
16344  {
16345  Vector<unsigned> node_name_r = root_local_node_names[j];
16346 
16347  // Check if this name node has been already done
16348  if (!done_name[node_name_r])
16349  {
16350  // Check whether this node is the
16351  // counter-part of the current name node
16352  if (node_name[0] == node_name_r[1] &&
16353  node_name[1] == node_name_r[0] &&
16354  node_name[2] == node_name_r[2] &&
16355  node_name[3] == node_name_r[3])
16356  {
16357  // Mark the name as node
16358  done_name[node_name_r] = true;
16359  // Store the index of the counter-part of
16360  // the current node name
16361  node_name_counter_part[i] = j;
16362  // ... and indicate the current node name
16363  // as the index of the counter-part
16364  node_name_counter_part[j] = i;
16365 #ifdef PARANOID
16366  // The node has been found
16367  found_both_names_node = true;
16368 #endif
16369  // Break the loop to find the
16370  // counter-part
16371  break;
16372  }
16373 
16374  } // if (!done_name[node_name_r])
16375 
16376  } // for (j < n_root_local_node_names)
16377 #ifdef PARANOID
16378  // Check whether the node counter-part was found
16379  if (!found_both_names_node)
16380  {
16381  std::ostringstream error_message;
16382  error_message
16383  <<"The counter-part of the current name node was "
16384  <<"not found,\nthe current node name is:\n"
16385  <<"iproc:("<<node_name[0]<<")\n"
16386  <<"jproc:("<<node_name[1]<<")\n"
16387  <<"ishd_bnd:("<<node_name[2]<<")\n"
16388  <<"index:("<<node_name[3]<<")\n";
16389  throw OomphLibError(error_message.str(),
16390  OOMPH_CURRENT_FUNCTION,
16391  OOMPH_EXCEPTION_LOCATION);
16392  } // if (!found_both_names_node)
16393 #endif
16394 
16395  } // if (!done_name[node_name])
16396 
16397  } // for (i < n_root_local_node_names)
16398 
16399  // -----------------------------------------------------------
16400  // Look for all the names of each node received and store them
16401  // in the "global node names" container
16402 
16403  // Keep track of the names of nodes already done
16404  done_name.clear();
16405  // loop over the names of the nodes received from all
16406  // processors
16407  for (unsigned i = 0; i < n_root_local_node_names; i++)
16408  {
16409  // Get the i-th node name
16410  Vector<unsigned> node_name = root_local_node_names[i];
16411 
16412  // Check if this name node has been already done
16413  if (!done_name[node_name])
16414  {
16415  // Store all the names of the current node
16416  Vector<Vector<unsigned> > all_node_names;
16417 
16418  // Add the name of the node as the initial node name
16419  all_node_names.push_back(node_name);
16420 
16421  // Get the index of the counter-part
16422  unsigned idx_c = node_name_counter_part[i];
16423  // Get the counter-part of the node name
16424  Vector<unsigned> node_name_r = root_local_node_names[idx_c];
16425 
16426  // Add the name of the counter-part of the node
16427  all_node_names.push_back(node_name_r);
16428  // We do not mark it as done since we are interested in
16429  // the names that the counter-part may generate
16430 
16431  // Get the number of names for the current node (two at
16432  // the first time)
16433  unsigned n_current_names = all_node_names.size();
16434  // Counter to ensure to visit all the names of the current
16435  // node
16436  unsigned icounter = 0;
16437 
16438  // Visit all the names of the current node
16439  while(icounter < n_current_names)
16440  {
16441  // Get the current node name
16442  Vector<unsigned> current_node_name = all_node_names[icounter];
16443 
16444  // Search for other names for the current name of the
16445  // node, but first check if this has been already
16446  // visited
16447  if (!done_name[current_node_name])
16448  {
16449  // Mark it as done
16450  done_name[current_node_name] = true;
16451 
16452  // loop over the names of the nodes (start from the
16453  // j+1 position, all previous node names have all
16454  // their names already assigned)
16455  for (unsigned j=i+1;j<n_root_local_node_names;j++)
16456  {
16457  // Get the j-th node name
16458  Vector<unsigned> other_node_name = root_local_node_names[j];
16459 
16460  // Is this name node already done
16461  if (!done_name[other_node_name])
16462  {
16463  // Is this another name for the current name node?
16464  if ((current_node_name[0] == other_node_name[0]) &&
16465  (current_node_name[4] == other_node_name[4]))
16466  {
16467  // Mark it as done. If we search again using the
16468  // "other_node_name" as the current node name we
16469  // are not going to find new nodes to add
16470  done_name[other_node_name] = true;
16471  // Before adding it check that it is not already
16472  // part of the names of the node
16473  Vector<Vector<unsigned> >::iterator it
16474  = std::find(all_node_names.begin(),
16475  all_node_names.end(),
16476  other_node_name);
16477  if (it==all_node_names.end())
16478  {
16479  all_node_names.push_back(other_node_name);
16480  // Get the index of the counter-part
16481  unsigned k = node_name_counter_part[j];
16482  // Get the counter-part of the node name
16483  Vector<unsigned> other_node_name_r =
16484  root_local_node_names[k];
16485  // Add the name of the counter-part of the
16486  // node only if it has not been previously
16487  // done
16488  if (!done_name[other_node_name_r])
16489  {
16490  all_node_names.push_back(other_node_name_r);
16491  }
16492 
16493  }
16494 
16495  } // // Is this another name for the current name
16496  // node?
16497 
16498  } // if (!done_name[other_node_name])
16499 
16500  } // for (j < n_root_local_node_names)
16501 
16502  } // if (!done_name[current_node_name])
16503 
16504  // Get the number of names
16505  n_current_names = all_node_names.size();
16506  // Increase the icounter to indicate we have visited the
16507  // current name of the node
16508  icounter++;
16509 
16510  } // while(icounter < n_current_names)
16511 
16512  // We now have all the names for the i-th global node
16513  root_global_node_names.push_back(all_node_names);
16514 
16515  } // if (!done_name[node_name])
16516 
16517  } // for (i < n_root_local_node_names)
16518 
16519  // -------------------------------------------------------------
16520  // Prepare the info to be sent to all processors. The number
16521  // of global nodes, the number of names for each global node,
16522  // and their respective names
16523  // -------------------------------------------------------------
16524 
16525  // Clear the container
16526  flat_packed_root_send_receive_udata.clear();
16527  // Get the number of global nodes
16528  const unsigned n_global_nodes = root_global_node_names.size();
16529  // ... and store this info. to be sent from root to all
16530  // processors
16531  flat_packed_root_send_receive_udata.push_back(n_global_nodes);
16532 
16533  // loop over the nodes
16534  for (unsigned i = 0; i < n_global_nodes; i++)
16535  {
16536  // Get the names of the i-th global node
16537  Vector<Vector<unsigned> > global_inode_names =
16538  root_global_node_names[i];
16539  // Get the number of names for the i-th global node
16540  const unsigned n_names_global_inode = global_inode_names.size();
16541  // ... and store this info. to be sent from root to all
16542  // processors
16543  flat_packed_root_send_receive_udata.push_back(n_names_global_inode);
16544  // loop over the names of the global i-th node
16545  for (unsigned j = 0; j < n_names_global_inode; j++)
16546  {
16547  // loop over the info. associated with each name
16548  for (unsigned k = 0; k < n_info_per_node_name; k++)
16549  {
16550  // Store the name info. of the current name in the
16551  // container to be sent from root to all processors
16552  flat_packed_root_send_receive_udata.
16553  push_back(global_inode_names[j][k]);
16554  } // for (k < n_info_per_node_name)
16555 
16556  } // for (j < n_names_inode)
16557 
16558  } // for (i < n_global_nodes)
16559 
16560  } // if (my_rank == root_processor)
16561 
16562  // ----------------------------------------------------------------
16563  // END: Unpackage the info. received on root. Compute the alias
16564  // of the nodes and prepare the info. to be sent back from
16565  // root to all processors
16566  // ----------------------------------------------------------------
16567 
16568  // ---------------------------------------------------------------
16569  // BEGIN: Send the info. back to all processors, unpackage the
16570  // info. and create the map from node name to global node
16571  // index
16572  // ---------------------------------------------------------------
16573  // The number of data that root send to other processors.
16574  unsigned root_n_udata_sent_to_all_proc =
16575  flat_packed_root_send_receive_udata.size();
16576 
16577  MPI_Bcast(&root_n_udata_sent_to_all_proc, // Data to send and
16578  // receive
16579  1, MPI_UNSIGNED, root_processor,
16580  comm_pt->mpi_comm());
16581 
16582  // Resize the container if this is a processor that receives data
16583  if (my_rank != root_processor)
16584  {
16585  flat_packed_root_send_receive_udata.
16586  resize(root_n_udata_sent_to_all_proc);
16587  }
16588 
16589  // Send the info. from root and receive it on all processors
16590  MPI_Bcast(&flat_packed_root_send_receive_udata[0], // Info. sent
16591  // from root to
16592  // all
16593  // processors
16594  root_n_udata_sent_to_all_proc, // Number of data sent
16595  // from root to each
16596  // procesor
16597  MPI_UNSIGNED,
16598  root_processor, // The processor that sends all the info.
16599  comm_pt->mpi_comm());
16600 
16601  // Counter to extract the info.
16602  counter = 0;
16603  // Read the number of global nodes
16604  const unsigned n_global_nodes =
16605  flat_packed_root_send_receive_udata[counter++];
16606  // Store the global names of the nodes
16607  // global_node_name[x][ ][ ] Global node number
16608  // global_node_name[ ][x][ ] Global node names
16609  // global_node_name[ ][ ][x] Global node info.
16610  //Vector<Vector<Vector<unsigned> > > global_node_names(n_global_nodes);
16611  // Resize the input vector
16612  global_node_names.resize(n_global_nodes);
16613  // Now loop until all global nodes info. has been read
16614  unsigned n_read_global_nodes = 0;
16615  while (n_read_global_nodes < n_global_nodes)
16616  {
16617  // Read the number of names for the current global node
16618  const unsigned n_names_global_inode =
16619  flat_packed_root_send_receive_udata[counter++];
16620  // Counter for the global node
16621  const unsigned i = n_read_global_nodes;
16622  // Resize the container
16623  global_node_names[i].resize(n_names_global_inode);
16624  // loop over the names of the global inode
16625  for (unsigned j = 0; j < n_names_global_inode; j++)
16626  {
16627  // Resize the container
16628  global_node_names[i][j].resize(n_info_per_node_name);
16629  // loop over the info. of the j-th node name of the i-th
16630  // global node
16631  for (unsigned k = 0; k < n_info_per_node_name; k++)
16632  {
16633  // Read the k-th node info. from the j-th node name of
16634  // the i-th global node
16635  global_node_names[i][j][k] =
16636  flat_packed_root_send_receive_udata[counter++];
16637 
16638  } // for (k < n_info_per_node_name)
16639 
16640  // Create the map from the node name to the global node
16641  // index
16642  Vector<unsigned> node_name(n_info_per_node_name-1);
16643  node_name[0] = global_node_names[i][j][0];
16644  node_name[1] = global_node_names[i][j][1];
16645  node_name[2] = global_node_names[i][j][2];
16646  node_name[3] = global_node_names[i][j][3];
16647  // Do not add the local index since it will not longer be
16648  // used. Additionally, we will not know the local node
16649  // index outside this method
16650  // node_name[4] = global_node_names[i][j][4];
16651  node_name_to_global_index[node_name] = i;
16652 
16653  } // for (j < n_names_global_inode)
16654 
16655  // Increase the counter for read global nodes
16656  n_read_global_nodes++;
16657 
16658  } // while (n_read_global_nodes < n_global_nodes)
16659 
16660 #ifdef PARANOID
16661  // Check we have read all the info.
16662  if (counter != root_n_udata_sent_to_all_proc)
16663  {
16664  std::ostringstream error_stream;
16665  error_stream
16666  <<"The info. received from root regarding the global names of "
16667  <<"the nodes\nwas not completely read.\n"
16668  << "The number of data sent/received from root is: ("
16669  <<root_n_udata_sent_to_all_proc<<")\n"
16670  <<"The number of data read from the received info. is: ("
16671  <<counter<<")\n\n";
16672  throw OomphLibError(error_stream.str(),
16673  OOMPH_CURRENT_FUNCTION,
16674  OOMPH_EXCEPTION_LOCATION);
16675  } // if (counter != root_n_udata_sent_to_all_proc)
16676 #endif
16677 
16678  // ---------------------------------------------------------------
16679  // END: Send the info. back to all processors, unpackage the info.
16680  // and create the map from node name to global node index
16681  // ---------------------------------------------------------------
16682 
16683  // ---------------------------------------------------------------
16684  // BEGIN: Add the info. from the global node names into the
16685  // info. of the local node names. We do this because the
16686  // local node names have pointers to the nodes.
16687  // Additionally, create a map from the node name to the
16688  // index of its global node
16689  // ---------------------------------------------------------------
16690 
16691  // Resize the global shared node pointers container
16692  global_shared_node_pt.resize(n_global_nodes, 0);
16693 
16694  // loop over the number of global nodes
16695  for (unsigned i = 0; i < n_global_nodes; i++)
16696  {
16697  // Flag to indicate that the iglobal node is part of the nodes
16698  // on the current processor
16699  bool is_this_a_local_node_name = false;
16700  unsigned local_node_number;
16701  // Get the number of names of the i-th global node
16702  const unsigned n_names_global_inode = global_node_names[i].size();
16703  // loop over the names of the i-th global node
16704  for (unsigned j = 0; j < n_names_global_inode; j++)
16705  {
16706  // Get the node name info.
16707  const unsigned iproc = global_node_names[i][j][0];
16708  local_node_number = global_node_names[i][j][4];
16709 
16710  // Check if this node name lives on this processor
16711  if (my_rank == iproc)
16712  {
16713  // The node is part of the local node names
16714  is_this_a_local_node_name = true;
16715  // Break
16716  break;
16717  } // if (my_rank == iproc)
16718 
16719  } // for (j < n_names_global_inode)
16720 
16721  // If the node is part of the local nodes then add the
16722  // additional names of the node in the local container
16723  if (is_this_a_local_node_name)
16724  {
16725 #ifdef PARANOID
16726  // Check that the global node include at least all the names
16727  // of the node on this processor
16728  const unsigned n_names_local_node =
16729  local_node_names[local_node_number].size();
16730  unsigned n_names_found_on_global_name_node = 0;
16731 #endif
16732 
16733  // Add the pointer of the node into the global shared node
16734  // pointers container
16735  global_shared_node_pt[i] = local_node_pt[local_node_number];
16736 
16737  // Add all the global names of the node onto the local node
16738  // names
16739 
16740  // loop again over the names of the i-th global node
16741  for (unsigned j = 0; j < n_names_global_inode; j++)
16742  {
16743  // Get the node name info.
16744  const unsigned iproc = global_node_names[i][j][0];
16745 
16746  // Is this a node name on this processor?
16747  if (iproc != my_rank)
16748  {
16749  // Add the name
16750  local_node_names[local_node_number].
16751  push_back(global_node_names[i][j]);
16752  }
16753 #ifdef PARANOID
16754  else
16755  {
16756  const unsigned jproc = global_node_names[i][j][1];
16757  const unsigned ishd_bnd = global_node_names[i][j][2];
16758  const unsigned idx = global_node_names[i][j][3];
16759  const unsigned n_local_node = global_node_names[i][j][4];
16760  // loop over the names of the local node
16761  for (unsigned k = 0; k < n_names_local_node; k++)
16762  {
16763  if ((local_node_names[local_node_number][k][0] == iproc) &&
16764  (local_node_names[local_node_number][k][1] == jproc) &&
16765  (local_node_names[local_node_number][k][2] == ishd_bnd) &&
16766  (local_node_names[local_node_number][k][3] == idx) &&
16767  (local_node_names[local_node_number][k][4] == n_local_node))
16768  {
16769  // Increase the number of local nodes found on the
16770  // global nodes
16771  n_names_found_on_global_name_node++;
16772  } // found global node on local nodes
16773 
16774  } // for (k < n_names_local_node)
16775 
16776  } // if (iproc != my_rank)
16777 #endif
16778 
16779  } // for (j < n_names_global_inode)
16780 
16781 #ifdef PARANOID
16782  // The number of local nodes names must be the same as the the
16783  // number of global nodes names associated with this processor
16784  // (my_rank, that start with iproc = my_rank)
16785  if (n_names_local_node != n_names_found_on_global_name_node)
16786  {
16787  std::ostringstream error_stream;
16788  error_stream
16789  <<"The local node names corresponding to the local "
16790  <<"node ("<< local_node_number << ") were\n"
16791  <<"not found on the global node names.\n\n"
16792  << "These are the names of the local node\n"
16793  << "Name k: iproc, jproc, ishd_bnd, idx. #node\n";
16794  for (unsigned k = 0; k < n_names_local_node; k++)
16795  {
16796  error_stream<<"Name("<<k<<"): "
16797  <<local_node_names[local_node_number][k][0]
16798  <<", "<<local_node_names[local_node_number][k][1]
16799  <<", "<<local_node_names[local_node_number][k][2]
16800  <<", "<<local_node_names[local_node_number][k][3]
16801  <<", "<<local_node_names[local_node_number][k][4]
16802  <<"\n";
16803  }
16804 
16805  error_stream
16806  << "\n\nThese are the names of the global node\n"
16807  << "Name k: iproc, jproc, ishd_bnd, idx. #node\n";
16808  for (unsigned k = 0; k < n_names_global_inode; k++)
16809  {
16810  error_stream<<"Name("<<k<<"): "
16811  <<global_node_names[i][k][0] <<", "
16812  <<global_node_names[i][k][1] <<", "
16813  <<global_node_names[i][k][2] <<", "
16814  <<global_node_names[i][k][3] <<", "
16815  <<global_node_names[i][k][4] <<"\n";
16816  }
16817 
16818  throw OomphLibError(error_stream.str(),
16819  OOMPH_CURRENT_FUNCTION,
16820  OOMPH_EXCEPTION_LOCATION);
16821  }
16822 #endif
16823 
16824  } // if (is_this_a_local_node_name)
16825 
16826  } // for (i < n_global_nodes)
16827 
16828  // ---------------------------------------------------------------
16829  // END: Add the info. from the global node names into the info.
16830  // of the local node names. We do this because the local
16831  // node names have pointers to the nodes
16832  // ---------------------------------------------------------------
16833 
16834  // ---------------------------------------------------------------
16835  // BEGIN: Fill the data structure other_proc_shd_bnd_node_pt with
16836  // the local nodes.
16837  // ---------------------------------------------------------------
16838 
16839  // Loop over the local nodes and fill the
16840  // other_proc_shd_bnd_node_pt container with the corresponding
16841  // info. NOTE: We are using the old size of the local node names,
16842  // before adding the names of the global nodes so we only loop
16843  // over the local nodes and not global.
16844 
16845  // Compute the local shared boudary id
16846  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
16847 
16848  // loop over the local nodes names
16849  for (unsigned i = 0 ; i < n_local_nodes; i++)
16850  {
16851  // Get the number of names for the i-th local node
16852  const unsigned n_names = local_node_names[i].size();
16853  // Get a pointer to the first name of the node found on this
16854  // processor (this ensures that the node lives on this
16855  // processor)
16856  Node* node_pt = local_node_pt[i];
16857  // loop over the names of the i-th local node and add an entry
16858  // to the other_proc_shd_bnd_node_pt structure
16859  for (unsigned j = 0; j < n_names; j++)
16860  {
16861  // Get the node name info.
16862  const unsigned iproc = local_node_names[i][j][0];
16863  const unsigned jproc = local_node_names[i][j][1];
16864  const unsigned ishd_bnd =
16865  local_node_names[i][j][2] - initial_shd_bnd_id;
16866  const unsigned index = local_node_names[i][j][3];
16867  // We can ignore the last entry, it was just used to compute
16868  // the global node number by the root processor
16869 
16870  // Get the smallest processor number
16871  if (iproc < jproc)
16872  {
16873  other_proc_shd_bnd_node_pt[iproc][jproc][ishd_bnd][index]=node_pt;
16874  }
16875  else
16876  {
16877  other_proc_shd_bnd_node_pt[jproc][iproc][ishd_bnd][index]=node_pt;
16878  }
16879 
16880  } // for (j < n_names)
16881 
16882  } // for (i < n_local_node_names)
16883 
16884  // ---------------------------------------------------------------
16885  // END: Fill the data structure other_proc_shd_bnd_node_pt with
16886  // the local nodes.
16887  // ---------------------------------------------------------------
16888 
16889 }
16890 
16891  //======================================================================
16892  // \short Get the original boundaries to which is associated each
16893  // shared node, and send the info. to the related processors. We
16894  // need to do this so that at the reset of halo(ed) info. stage,
16895  // the info. is updated
16896 template <class ELEMENT>
16899  Vector<Vector<Vector<unsigned> > > &global_node_names,
16900  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
16901  Vector<Node*> &global_shared_node_pt)
16902 {
16903  // Get the rank and number of processors
16904  const unsigned nproc = this->communicator_pt()->nproc();
16905  const unsigned my_rank = this->communicator_pt()->my_rank();
16906 
16907  // The number of nodes on shared boundaries
16908  const unsigned n_nodes_on_shd_bnds = global_node_names.size();
16909  // ---------------------------------------------------------
16910  // BEGIN: Get the shared nodes between each of processors
16911  // ---------------------------------------------------------
16912 
16913  // Store the nodes on shared boundaries in this processor with other
16914  // processors
16915  Vector<std::set<Node*> > node_on_shd_bnd_pt(nproc);
16916 
16917  // A map to get access to the global shared node number from the
16918  // node pointer
16919  std::map<Node*, unsigned> node_pt_to_global_shd_bnd_index;
16920 
16921  // loop over the global nodes names and get only those in this
16922  // processor
16923  for (unsigned i = 0; i < n_nodes_on_shd_bnds; i++)
16924  {
16925  // Get the number of names of the current node on shared
16926  // boundaries
16927  const unsigned n_names = global_node_names[i].size();
16928  // loop over the names
16929  for (unsigned j = 0; j < n_names; j++)
16930  {
16931  // Store the node name
16932  Vector<unsigned> node_name(4);
16933  node_name[0] = global_node_names[i][j][0];
16934  node_name[1] = global_node_names[i][j][1];
16935  node_name[2] = global_node_names[i][j][2];
16936  node_name[3] = global_node_names[i][j][3];
16937 
16938  // Check whether the node is in the current processor
16939  if (node_name[0]==my_rank)
16940  {
16941  // Check with which processor the node is shared
16942  const unsigned jproc = node_name[1];
16943 
16944 #ifdef PARANOID
16945  std::map<Vector<unsigned>, unsigned>::iterator it =
16946  node_name_to_global_index.find(node_name);
16947  if (it!=node_name_to_global_index.end())
16948  {
16949  // Check whether the global node index correspond with that
16950  // of the current global node name
16951  if (i!=(*it).second)
16952  {
16953  std::ostringstream error_message;
16954  error_message
16955  <<"The global node number "<<(*it).second
16956  <<") obtained from the current node\n"
16957  <<"name is not the same as the current node number ("
16958  <<i<<").\n\n"
16959  <<"Node name:\n"
16960  <<"iproc:"<<node_name[0]<<"\n"
16961  <<"jproc:"<<node_name[1]<<"\n"
16962  <<"shd_bnd_id:"<<node_name[2]<<"\n"
16963  <<"index:"<<node_name[3]<<"\n\n";
16964  throw OomphLibError(error_message.str(),
16965  OOMPH_CURRENT_FUNCTION,
16966  OOMPH_EXCEPTION_LOCATION);
16967  }
16968 
16969  }
16970  else
16971  {
16972  std::ostringstream error_message;
16973  error_message
16974  <<"The node name is not registerd as living in this processor.\n"
16975  <<"Node name:\n"
16976  <<"iproc:"<<node_name[0]<<"\n"
16977  <<"jproc:"<<node_name[1]<<"\n"
16978  <<"shd_bnd_id:"<<node_name[2]<<"\n"
16979  <<"index:"<<node_name[3]<<"\n\n";
16980  throw OomphLibError(error_message.str(),
16981  OOMPH_CURRENT_FUNCTION,
16982  OOMPH_EXCEPTION_LOCATION);
16983  }
16984 
16985 #endif // #ifdef PARANOID
16986 
16987  // Get the node pointer
16988  Node* node_pt = global_shared_node_pt[i];
16989 
16990 #ifdef PARANOID
16991  if (node_pt == 0)
16992  {
16993  std::ostringstream error_message;
16994  error_message
16995  <<"There is not global shared node within this\n"
16996  <<"global node number ("<<i<<"). The global shared\n"
16997  <<"node pointer is null\n\n";
16998  throw OomphLibError(error_message.str(),
16999  OOMPH_CURRENT_FUNCTION,
17000  OOMPH_EXCEPTION_LOCATION);
17001  }
17002 #endif // #ifdef PARANOID
17003 
17004  // Add the node to the nodes on shared boundaries in this
17005  // processor
17006  node_on_shd_bnd_pt[jproc].insert(node_pt);
17007 
17008  // And store the global node index
17009  node_pt_to_global_shd_bnd_index[node_pt] = i;
17010 
17011  } // if (node_name[0]==my_rank)
17012  else if (node_name[1]==my_rank)
17013  {
17014  // Check with which processor the node is shared
17015  const unsigned jproc = node_name[0];
17016 
17017 #ifdef PARANOID
17018  std::map<Vector<unsigned>, unsigned>::iterator it =
17019  node_name_to_global_index.find(node_name);
17020  if (it!=node_name_to_global_index.end())
17021  {
17022  // Check whether the global node index correspond with that
17023  // of the current global node name
17024  if (i!=(*it).second)
17025  {
17026  std::ostringstream error_message;
17027  error_message
17028  <<"The global node number "<<(*it).second
17029  <<") obtained from the current node\n"
17030  <<"name is not the same as the current node number ("
17031  <<i<<").\n\n"
17032  <<"Node name:\n"
17033  <<"iproc:"<<node_name[0]<<"\n"
17034  <<"jproc:"<<node_name[1]<<"\n"
17035  <<"shd_bnd_id:"<<node_name[2]<<"\n"
17036  <<"index:"<<node_name[3]<<"\n\n";
17037  throw OomphLibError(error_message.str(),
17038  OOMPH_CURRENT_FUNCTION,
17039  OOMPH_EXCEPTION_LOCATION);
17040  }
17041 
17042  }
17043  else
17044  {
17045  std::ostringstream error_message;
17046  error_message
17047  <<"The node name is not registerd as living in this processor.\n"
17048  <<"Node name:\n"
17049  <<"iproc:"<<node_name[0]<<"\n"
17050  <<"jproc:"<<node_name[1]<<"\n"
17051  <<"shd_bnd_id:"<<node_name[2]<<"\n"
17052  <<"index:"<<node_name[3]<<"\n\n";
17053  throw OomphLibError(error_message.str(),
17054  OOMPH_CURRENT_FUNCTION,
17055  OOMPH_EXCEPTION_LOCATION);
17056  }
17057 
17058 #endif // #ifdef PARANOID
17059 
17060  // Get the node pointer
17061  Node* node_pt = global_shared_node_pt[i];
17062 
17063 #ifdef PARANOID
17064  if (node_pt == 0)
17065  {
17066  std::ostringstream error_message;
17067  error_message
17068  <<"There is not global shared node within this\n"
17069  <<"global node number ("<<i<<"). The global shared\n"
17070  <<"node pointer is null\n\n";
17071  throw OomphLibError(error_message.str(),
17072  OOMPH_CURRENT_FUNCTION,
17073  OOMPH_EXCEPTION_LOCATION);
17074  }
17075 #endif // #ifdef PARANOID
17076 
17077  // Add the node to the nodes on shared boundaries in this
17078  // processor
17079  node_on_shd_bnd_pt[jproc].insert(node_pt);
17080 
17081  // And store the global node index
17082  node_pt_to_global_shd_bnd_index[node_pt] = i;
17083 
17084  }
17085 
17086  } // for (j < n_names)
17087 
17088  } // for (i < n_nodes_on_shd_bnds)
17089 
17090  // ---------------------------------------------------------
17091  // END: Get the shared nodes between each of processors
17092  // ---------------------------------------------------------
17093 
17094  // ---------------------------------------------------------
17095  // BEGIN: Get the original boundaries associated to each
17096  // node on a shared boundary
17097  // ---------------------------------------------------------
17098 
17099  // Store the global shared node number
17100  Vector<Vector<unsigned> > global_node_on_shared_bound(nproc);
17101  // Store the boundaries associated with the global shared node
17102  // number
17103  Vector<Vector<Vector<unsigned> > > global_node_original_boundaries(nproc);
17104  // Store the zeta boundary coordinate of the nodes on original
17105  // boundaries
17106  Vector<Vector<Vector<double> > > global_node_zeta_coordinate(nproc);
17107 
17108  // loop over the processors
17109  for (unsigned iproc = 0; iproc < nproc; iproc++)
17110  {
17111  // Get the nodes added to be shared with the iproc processor
17112  std::set<Node*> nodes_shared_pt = node_on_shd_bnd_pt[iproc];
17113 
17114  // loop over the nodes
17115  for (std::set<Node*>::iterator it = nodes_shared_pt.begin();
17116  it!=nodes_shared_pt.end(); it++)
17117  {
17118  // Get the node
17119  Node* node_pt = (*it);
17120  // Store the boundaries on which it is stored
17121  Vector<unsigned> on_original_boundaries;
17122  // For each boundary get the corresponding z value of the node
17123  // on the boundary
17124  Vector<double> zeta_coordinate;
17125  // Get the number of boudandaries
17126  const unsigned n_bnd=this->initial_shared_boundary_id();
17127  // loop over the boundaries and register the boundaries to which
17128  // it is associated
17129  for (unsigned bb = 0; bb < n_bnd; bb++)
17130  {
17131  // Is the node on original boundary bb?
17132  if (node_pt->is_on_boundary(bb))
17133  {
17134  // Then save it as being on boundary bb
17135  on_original_boundaries.push_back(bb);
17136  // Get the boundary coordinate
17137  Vector<double> zeta(1);
17138  node_pt->get_coordinates_on_boundary(bb, zeta);
17139  // Save the boundary coordinate
17140  zeta_coordinate.push_back(zeta[0]);
17141  }
17142 
17143  } // for (bb < n_bnd)
17144 
17145  // Is the node on an original boundary
17146  if (on_original_boundaries.size()>0)
17147  {
17148  // Get the global shared node number
17149  std::map<Node*,unsigned>::iterator it_index =
17150  node_pt_to_global_shd_bnd_index.find(node_pt);
17151 #ifdef PARANOID
17152  if (it_index==node_pt_to_global_shd_bnd_index.end())
17153  {
17154  std::ostringstream error_message;
17155  error_message
17156  <<"We could not find the global shared node index associated\n"
17157  <<"with the node pointer with vertices coordinates:\n"
17158  <<"("<<node_pt->x(0)<<", "<<node_pt->x(1)<<")\n\n";
17159  throw OomphLibError(error_message.str(),
17160  OOMPH_CURRENT_FUNCTION,
17161  OOMPH_EXCEPTION_LOCATION);
17162  }
17163 #endif
17164  // The global shared node index
17165  const unsigned global_shared_node_number = (*it_index).second;
17166  // Store the global shared node number
17167  global_node_on_shared_bound[iproc].push_back(global_shared_node_number);
17168  // And store the original boundaries to which it is associated
17169  global_node_original_boundaries[iproc].
17170  push_back(on_original_boundaries);
17171  // and the corresponding zeta coordinate
17172  global_node_zeta_coordinate[iproc].push_back(zeta_coordinate);
17173  }
17174 
17175  } // loop over nodes on shared boundaries with iproc
17176 
17177  } // for (iproc < nproc)
17178 
17179  // ---------------------------------------------------------
17180  // END: Get the original boundaries associated to each
17181  // node on a shared boundary
17182  // ---------------------------------------------------------
17183 
17184  // ---------------------------------------------------------
17185  // BEGIN: Send the info. to the corresponding processors,
17186  // package the info, send it and receive it in the
17187  // corresponding processor, unpackage and set the
17188  // boundaries associated with the received nodes
17189  // ---------------------------------------------------------
17190 
17191  // Get the communicator of the mesh
17192  OomphCommunicator* comm_pt = this->communicator_pt();
17193 
17194  // Set MPI info
17195  MPI_Status status;
17196  MPI_Request request;
17197 
17198  // loop over the processors
17199  for (unsigned iproc = 0; iproc < nproc; iproc++)
17200  {
17201  // The number of nodes shared between the pair of processors
17202  const unsigned n_shd_nodes_my_rank_iproc =
17203  node_on_shd_bnd_pt[iproc].size();
17204 
17205  // Are there shared nodes between these pair of processors
17206  // (my_rank, iproc)? Also ensure not to send info. within myself
17207  if (n_shd_nodes_my_rank_iproc > 0 && iproc != my_rank)
17208  {
17209  // The flat package to send the info, to the iproc processor
17210  Vector<unsigned> flat_package_unsigned_send;
17211  // The very first entry is the number of nodes shared by the
17212  // pair of processors (my_rank, iproc)
17213  flat_package_unsigned_send.push_back(n_shd_nodes_my_rank_iproc);
17214 
17215  // Get the number of shared nodes on original boundaries
17216  const unsigned n_global_shared_node_on_original_boundary =
17217  global_node_on_shared_bound[iproc].size();
17218 
17219  // The second data is the number of shared nodes on original
17220  // boundaries
17221  flat_package_unsigned_send.
17222  push_back(n_global_shared_node_on_original_boundary);
17223 
17224  // ... also send the zeta coordinates associated with the
17225  // original boundaries
17226  Vector<double> flat_package_double_send;
17227 
17228  // loop over the nodes shared between this pair of processors
17229  for (unsigned i = 0; i < n_global_shared_node_on_original_boundary; i++)
17230  {
17231  // Get the global shared node index
17232  const unsigned global_shared_node_index =
17233  global_node_on_shared_bound[iproc][i];
17234 
17235  // Put in the package the shared node index of the current
17236  // node
17237  flat_package_unsigned_send.push_back(global_shared_node_index);
17238 
17239  // Get the original boundaries to which the node is associated
17240  Vector<unsigned> on_original_boundaries =
17241  global_node_original_boundaries[iproc][i];
17242 
17243  // Get the associated zeta boundary coordinates
17244  Vector<double> zeta_coordinate =
17245  global_node_zeta_coordinate[iproc][i];
17246 
17247  // Get the number of original boundaries to which the node is
17248  // associated
17249  const unsigned n_original_boundaries =
17250  on_original_boundaries.size();
17251 
17252  // Put in the package the number of original boundaries the
17253  // node is associated
17254  flat_package_unsigned_send.push_back(n_original_boundaries);
17255 
17256  // loop over the original boundaries ids and include them in
17257  // the package
17258  for (unsigned j = 0; j < n_original_boundaries; j++)
17259  {
17260  // Put in the package each of the original boundaries to
17261  // which it is associated
17262  flat_package_unsigned_send.push_back(on_original_boundaries[j]);
17263  // The zeta coordinate on the boundary
17264  flat_package_double_send.push_back(zeta_coordinate[j]);
17265  } // for (j < n_original_boundaries)
17266 
17267  } // for (i < n_global_shared_node_on_original_boundary)
17268 
17269  // Send data UNSIGNED -----------------------------------------
17270  // Get the size of the package to communicate to the iproc
17271  // processor
17272  const unsigned n_udata_send = flat_package_unsigned_send.size();
17273  int n_udata_send_int = n_udata_send;
17274 
17275  // Send/receive data to/from iproc processor
17276  MPI_Isend(&n_udata_send_int,1,MPI_UNSIGNED,
17277  iproc,1,comm_pt->mpi_comm(), &request);
17278 
17279  int n_udata_received_int = 0;
17280  MPI_Recv(&n_udata_received_int,1,MPI_UNSIGNED,
17281  iproc,1,comm_pt->mpi_comm(),&status);
17282  MPI_Wait(&request,MPI_STATUS_IGNORE);
17283 
17284  if (n_udata_send!=0)
17285  {
17286  MPI_Isend(&flat_package_unsigned_send[0],
17287  n_udata_send,MPI_UNSIGNED,
17288  iproc,2,comm_pt->mpi_comm(),&request);
17289  }
17290 
17291  const unsigned n_udata_received =
17292  static_cast<unsigned>(n_udata_received_int);
17293 
17294  // Where to receive the data from the iproc processor
17295  Vector<unsigned> flat_package_unsigned_receive(n_udata_received);
17296 
17297  if (n_udata_received!=0)
17298  {
17299  MPI_Recv(&flat_package_unsigned_receive[0],
17300  n_udata_received,MPI_UNSIGNED,
17301  iproc,2,comm_pt->mpi_comm(),&status);
17302  }
17303 
17304  if (n_udata_send!=0)
17305  {
17306  MPI_Wait(&request,MPI_STATUS_IGNORE);
17307  }
17308 
17309  // Send data DOUBLE -----------------------------------------
17310  // Get the size of the package to communicate to the iproc
17311  // processor
17312  const unsigned n_ddata_send = flat_package_double_send.size();
17313  int n_ddata_send_int = n_ddata_send;
17314 
17315  // Send/receive data to/from iproc processor
17316  MPI_Isend(&n_ddata_send_int,1,MPI_UNSIGNED,
17317  iproc,1,comm_pt->mpi_comm(), &request);
17318 
17319  int n_ddata_received_int = 0;
17320  MPI_Recv(&n_ddata_received_int,1,MPI_UNSIGNED,
17321  iproc,1,comm_pt->mpi_comm(),&status);
17322  MPI_Wait(&request,MPI_STATUS_IGNORE);
17323 
17324  if (n_ddata_send!=0)
17325  {
17326  MPI_Isend(&flat_package_double_send[0],
17327  n_ddata_send,MPI_DOUBLE,
17328  iproc,2,comm_pt->mpi_comm(),&request);
17329  }
17330 
17331  const unsigned n_ddata_received =
17332  static_cast<unsigned>(n_ddata_received_int);
17333 
17334  // Where to receive the data from the iproc processor
17335  Vector<double> flat_package_double_receive(n_ddata_received);
17336 
17337  if (n_ddata_received!=0)
17338  {
17339  MPI_Recv(&flat_package_double_receive[0],
17340  n_ddata_received,MPI_DOUBLE,
17341  iproc,2,comm_pt->mpi_comm(),&status);
17342  }
17343 
17344  if (n_ddata_send!=0)
17345  {
17346  MPI_Wait(&request,MPI_STATUS_IGNORE);
17347  }
17348 
17349  // Unpackage -------------------------------------------------
17350  // ... and associate the nodes to the corresponding original
17351  // boundaries
17352 
17353  // The number of nodes to be received
17354  unsigned n_shared_nodes_received = flat_package_unsigned_receive[0];
17355 
17356  // Increase and decrease the number of received shared nodes to
17357  // avoid the warning when compiling without PARANOID
17358  n_shared_nodes_received++;
17359  n_shared_nodes_received--;
17360 
17361 #ifdef PARANOID
17362  if (n_shd_nodes_my_rank_iproc != n_shared_nodes_received)
17363  {
17364  std::ostringstream error_message;
17365  error_message
17366  <<"The number of shared nodes between the pair of processors is\n"
17367  <<"not the same\n"
17368  <<"N.shared nodes proc ("<<my_rank<<") with proc ("<<iproc<<"): ("
17369  <<n_shd_nodes_my_rank_iproc<<"\n"
17370  <<"N.shared nodes proc ("<<iproc<<") with proc ("<<my_rank<<"): ("
17371  <<n_shared_nodes_received<<"\n\n"
17372  <<"You should have got the same error in proc: ("<<iproc<<")\n\n";
17373  throw OomphLibError(error_message.str(),
17374  OOMPH_CURRENT_FUNCTION,
17375  OOMPH_EXCEPTION_LOCATION);
17376  } // if (n_shd_nodes_my_rank_iproc != n_shared_nodes_received)
17377 #endif
17378 
17379  // Skip the number of nodes on shared boundaries on original
17380  // boundaries received (that is why next lines are commented)
17381 
17382  // The number of nodes on shared boundaries on original
17383  // boundaries
17384  //const unsigned n_shared_nodes_on_original_boundaries_received =
17385  // flat_package_unsigned_receive[1];
17386 
17387  // loop over the received info.
17388  unsigned current_index_data = 2;
17389  unsigned current_index_ddata = 0;
17390  while(current_index_data < n_udata_received)
17391  {
17392  // The global shared node number
17393  const unsigned global_shared_node_index =
17394  flat_package_unsigned_receive[current_index_data++];
17395 
17396  // The pointer to the node
17397  Node* node_pt = 0;
17398 
17399  // The number of original boundaries the node is associated
17400  // with
17401  const unsigned n_original_boundaries =
17402  flat_package_unsigned_receive[current_index_data++];
17403 
17404  // Get the node pointer
17405  node_pt = global_shared_node_pt[global_shared_node_index];
17406 #ifdef PARANOID
17407  if (node_pt == 0)
17408  {
17409  std::ostringstream error_message;
17410  error_message
17411  <<"The global shared node ("<<global_shared_node_index<<") "
17412  <<"could not be found in this processor!!!\n"
17413  <<"However, it was found in processor ("<<iproc<<"). The "
17414  <<"data may be no synchronised,\ntherefore "
17415  <<"we may be looking for a global shared node number that "
17416  <<"do not\ncorrespond with the one that was sent by "
17417  <<"processor ("<<iproc<<")\n\n";
17418  throw OomphLibError(error_message.str(),
17419  OOMPH_CURRENT_FUNCTION,
17420  OOMPH_EXCEPTION_LOCATION);
17421  }
17422 #endif // #ifdef PARANOID
17423 
17424  // loop over the number of original boundaries and associate
17425  // the node to each of those boundaries
17426  for (unsigned i = 0; i < n_original_boundaries; i++)
17427  {
17428  // Get the original boundary to which the node is associated
17429  // with
17430  const unsigned original_bound_id =
17431  flat_package_unsigned_receive[current_index_data++];
17432 
17433  // Associate the node with the boundary
17434  this->add_boundary_node(original_bound_id, node_pt);
17435 
17436  // Get the zeta boundary coordinate
17437  Vector<double> zeta(1);
17438  zeta[0] = flat_package_double_receive[current_index_ddata++];
17439  node_pt->set_coordinates_on_boundary(original_bound_id, zeta);
17440  }
17441 
17442  } // while(current_data < n_data_received)
17443 
17444  } // if ((node_on_shd_bnd_pt(iproc) > 0) && iproc!=my_rank)
17445 
17446  } // for (iproc < nproc)
17447 
17448  // ---------------------------------------------------------
17449  // END: Send the info. to the corresponding processors,
17450  // package the info, send it and receive it in the
17451  // corresponding processor, unpackage and set the
17452  // boundaries associated with the received nodes
17453  // ---------------------------------------------------------
17454 
17455 }
17456 
17457  //======================================================================
17458  // \short In charge of creating additional halo(ed) elements on those
17459  // processors that have no shared boundaries in common but have
17460  // shared nodes
17461  // ======================================================================
17462 template <class ELEMENT>
17464  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
17465  &other_proc_shd_bnd_node_pt,
17466  Vector<Vector<Node *> > &iproc_currently_created_nodes_pt,
17467  Vector<Vector<Vector<unsigned> > > &global_node_names,
17468  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
17469  Vector<Node*> &global_shared_node_pt)
17470  {
17471  // Get the rank and number of processors
17472  const unsigned nproc = this->communicator_pt()->nproc();
17473  const unsigned my_rank = this->communicator_pt()->my_rank();
17474 
17475  // ---------------------------------------------------------------
17476  // BEGIN: Create a map to check whether a node is on the global
17477  // shared nodes. Also set a map to obtain the global
17478  // shared node index (this index is the same as the global
17479  // node name)
17480  // ---------------------------------------------------------------
17481  std::map<Node*, bool> is_global_shared_node;
17482  std::map<Node*, unsigned> global_shared_node_index;
17483 
17484  // Get the number of global shared nodes
17485  const unsigned n_global_shared_nodes = global_shared_node_pt.size();
17486  // loop over the global shared nodes
17487  for (unsigned i = 0; i < n_global_shared_nodes; i++)
17488  {
17489  // Get the node
17490  Node* node_pt = global_shared_node_pt[i];
17491  // Indicate this is a shared global node
17492  is_global_shared_node[node_pt] = true;
17493  // Set the map to obtain the index of the global shared node
17494  global_shared_node_index[node_pt] = i;
17495 
17496  } // for (i < n_global_shared_nodes)
17497 
17498  // ---------------------------------------------------------------
17499  // END: Create a map to check whether a node is on the global
17500  // shared nodes. Also set a map to obtain the global
17501  // shared node index (this index is the same as the global
17502  // node name)
17503  // ---------------------------------------------------------------
17504 
17505  // ---------------------------------------------------------------
17506  // BEGIN: Loop over the haloed elements and check whether the nodes
17507  // on the haloed elements are part of the global shared
17508  // nodes. If that is the case then check whether the
17509  // element should be sent to the processors with which the
17510  // node is shared
17511  // ---------------------------------------------------------------
17512 
17513  // Elements that may be sent to other processors
17514  Vector<std::set<GeneralisedElement*> > additional_elements_pt(nproc);
17515 
17516  // loop over the processors
17517  for (unsigned iproc = 0; iproc < nproc; iproc++)
17518  {
17519  if (iproc!=my_rank)
17520  {
17521  // Get the haloed element with iproc
17522  Vector<GeneralisedElement*> haloed_ele_pt =
17523  this->root_haloed_element_pt(iproc);
17524 
17525  // Get the number of haloed elements
17526  const unsigned n_haloed_ele =
17527  this->nroot_haloed_element(iproc);
17528 
17529  // loop over the haloed elements with iproc
17530  for (unsigned ihd = 0; ihd < n_haloed_ele; ihd++)
17531  {
17532  // A pointer to the generalised element
17533  GeneralisedElement* gele_pt = haloed_ele_pt[ihd];
17534  // Get the finite element representation of the element
17535  FiniteElement* ele_pt = dynamic_cast<FiniteElement*>(gele_pt);
17536  // Get the number of nodes
17537  const unsigned n_nodes = ele_pt->nnode();
17538  // loop over the nodes of the element
17539  for (unsigned n = 0; n < n_nodes; n++)
17540  {
17541  // Get the node
17542  Node* node_pt = ele_pt->node_pt(n);
17543  // Is the node a global shared node?
17544  if (is_global_shared_node[node_pt])
17545  {
17546  // Get the index of the global shared node
17547  const unsigned global_index = global_shared_node_index[node_pt];
17548  // Get the global names of the node
17549  Vector<Vector<unsigned> > iglobal_names =
17550  global_node_names[global_index];
17551 
17552  // Get the number of names
17553  const unsigned n_names = iglobal_names.size();
17554  // loop over the names and check which processors share
17555  // this node (the processors to which the element may be
17556  // sent
17557  for (unsigned j = 0; j < n_names; j++)
17558  {
17559  // Get the processors to which the element should be
17560  // sent
17561  const unsigned proc1 = iglobal_names[j][0];
17562  const unsigned proc2 = iglobal_names[j][1];
17563  // Add the element to the set of additional elements to
17564  // sent from proc1 to proc2
17565  additional_elements_pt[proc1].insert(gele_pt);
17566  additional_elements_pt[proc2].insert(gele_pt);
17567 
17568  } // for (j < n_names)
17569 
17570  } // if (is_global_shared_node[node_pt])
17571 
17572  } // for (n < n_nodes)
17573 
17574  } // for (ihd < n_haloed_ele)
17575 
17576  } // if (iproc!=my_rank)
17577 
17578  } // for (iproc < nproc)
17579 
17580  // ---------------------------------------------------------------
17581  // Now check whether the element should really be sent to the
17582  // indicated processors
17583 
17584  // The elements from this (my_rank) processor that will be sent to
17585  // other processors
17586  Vector<Vector<FiniteElement*> > send_haloed_ele_pt(nproc);
17587 
17588  // loop over the processors
17589  for (unsigned iproc = 0; iproc < nproc; iproc++)
17590  {
17591  if (iproc!=my_rank)
17592  {
17593  // Get the set of element that may be sent to the iproc
17594  // processor
17595  std::set<GeneralisedElement*> iproc_ele_pt =
17596  additional_elements_pt[iproc];
17597  // loop over the element that may be sent to the iproc
17598  // processor
17599  for (std::set<GeneralisedElement*>::iterator it =
17600  iproc_ele_pt.begin(); it!=iproc_ele_pt.end(); it++)
17601  {
17602  // Get a pointer to the element
17603  GeneralisedElement* gele_pt = (*it);
17604 
17605  // Get the haloed element with iproc
17606  Vector<GeneralisedElement*> haloed_ele_pt =
17607  this->root_haloed_element_pt(iproc);
17608 
17609  // Get the number of haloed elements
17610  const unsigned n_haloed_ele = this->nroot_haloed_element(iproc);
17611 
17612  // Flag to indicate whether the element has been already sent
17613  // to the iproc processor
17614  bool send_ele_to_iproc_processor = true;
17615  // loop over the haloed elements with iproc and check whether
17616  // the element has been already sent to iproc (if it is
17617  // already a haloed element with iproc then it has been
17618  // already sent)
17619  for (unsigned ihd = 0; ihd < n_haloed_ele; ihd++)
17620  {
17621  // A pointer to the generalised element
17622  GeneralisedElement* ghd_ele_pt = haloed_ele_pt[ihd];
17623  if (gele_pt == ghd_ele_pt)
17624  {
17625  // Mark the element as not required to be sent
17626  send_ele_to_iproc_processor = false;
17627  // Break the loop that searchs for the element on the
17628  // haloed elements with iproc
17629  break;
17630  }
17631 
17632  } // for (ihd < n_haloed_ele)
17633 
17634  // Do we need to sent the element?
17635  if (send_ele_to_iproc_processor)
17636  {
17637  // Get the finite element representation of the element
17638  FiniteElement* ele_pt = dynamic_cast<FiniteElement*>(gele_pt);
17639  // Add the element to those that will be sent to the iproc
17640  // processor
17641  send_haloed_ele_pt[iproc].push_back(ele_pt);
17642  }
17643 
17644  } // loop over the elements that may be sent to the iproc
17645  // processor
17646 
17647  } // if (iproc!=my_rank)
17648 
17649  } // for (iproc < nproc)
17650 
17651  // ---------------------------------------------------------------
17652  // END: Loop over the haloed element and check whether the nodes
17653  // on the haloed elements are part of the global shared
17654  // nodes. If that is the case then check whether the element
17655  // should be sent to the processors with which the node is
17656  // shared
17657  // ---------------------------------------------------------------
17658 
17659  // ============================================================
17660  // Now send the additional elements
17661  // ============================================================
17662  // Loop over the processors to send data
17663  for (unsigned iproc = 0; iproc < nproc; iproc++)
17664  {
17665  // There are no elements to send with myself
17666  if (iproc != my_rank)
17667  {
17668  // Get the number of additional haloed elements to send
17669  const unsigned n_additional_haloed_ele =
17670  send_haloed_ele_pt[iproc].size();
17671 
17672  // Clear send and receive buffers
17673  Flat_packed_unsigneds.clear();
17674  Flat_packed_doubles.clear();
17675 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17677 #endif
17678 
17679  // The very first data of the flat packed is the number of
17680  // additional haloed elements, this will be the number of
17681  // additional halo elements to create on the receiver processor
17682  Flat_packed_unsigneds.push_back(n_additional_haloed_ele);
17683 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17684  std::stringstream junk;
17685  junk << "Number of haloed elements " << nhaloed_ele;
17686  Flat_packed_unsigneds_string.push_back(junk.str());
17687 #endif
17688 
17689  // Loop over the additioanl haloed elements
17690  for (unsigned e = 0; e < n_additional_haloed_ele; e++)
17691  {
17692  // Get pointer to the additional haloed element
17693  FiniteElement* ele_pt = send_haloed_ele_pt[iproc][e];
17694  const unsigned nroot_haloed_ele =
17695  this->nroot_haloed_element(iproc);
17696 
17697  // Check if the element has been already added to the
17698  // halo(ed) scheme
17699 
17700  // Get the generalised version of the element
17701  GeneralisedElement *gen_ele_pt = ele_pt;
17702  // Try to add the haloed element
17703  const unsigned haloed_ele_index =
17704  this->try_to_add_root_haloed_element_pt(iproc, gen_ele_pt);
17705 
17706  // Was the element added or only returned the index of the
17707  // element
17708  if (nroot_haloed_ele == haloed_ele_index)
17709  {
17710  Flat_packed_unsigneds.push_back(1);
17711 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17712  Flat_packed_unsigneds_string.push_back("Haloed element needs to be constructed");
17713 #endif
17714 
17715  // Get additional info. related with the haloed element
17716  get_required_elemental_information_helper(iproc, ele_pt);
17717 
17718  // Get the nodes on the element
17719  const unsigned nnodes = ele_pt->nnode();
17720  for (unsigned j = 0; j < nnodes; j++)
17721  {
17722  Node* node_pt = ele_pt->node_pt(j);
17723 
17724  // Package the info. of the nodes
17725  // The destination processor goes in the arguments
17726  add_haloed_node_helper(iproc, node_pt);
17727 
17728  } // for (j < nnodes)
17729 
17730  } // add the element and send its nodes
17731  else // The haloed element already exists
17732  {
17733  Flat_packed_unsigneds.push_back(0);
17734 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17735  Flat_packed_unsigneds_string.push_back("Haloed element already exists");
17736 #endif
17737  Flat_packed_unsigneds.push_back(haloed_ele_index);
17738 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17739  Flat_packed_unsigneds_string.push_back("Index of existing haloed element");
17740 #endif
17741  } // else (next_haloed_ele == external_haloed_ele_index)
17742 
17743  } // for (e < n_additional_haloed_ele)
17744 
17745  // Send and received the additional haloed elements (all
17746  // processors send and receive)
17747 
17748  // The processor to which send the elements
17749  int send_proc = static_cast<int>(iproc);
17750  // The processor from which receive the elements
17751  int recv_proc = static_cast<int>(iproc);
17752  send_and_receive_elements_nodes_info(send_proc, recv_proc);
17753 
17754  // Reset the counters
17757 
17758  // Get the number of additional halo element to be created
17759  const unsigned n_additional_halo_ele =
17761 
17762 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17764  << " Number of elements need to be constructed "
17766  << std::endl;
17767 #endif
17768 
17769  // Create the additional halo elements
17770  for (unsigned e = 0; e < n_additional_halo_ele; e++)
17771  {
17772  // Create halo element from received info. of "iproc"
17773  // processor on the current processor
17774  create_halo_element(iproc,
17775  iproc_currently_created_nodes_pt[iproc],
17776  other_proc_shd_bnd_node_pt,
17777  global_node_names,
17778  node_name_to_global_index,
17779  global_shared_node_pt);
17780 
17781  } // for (e < n_additional_halo_ele)
17782 
17783  } // if (iproc != my_rank)
17784 
17785  } // for (iproc < nproc)
17786 
17787  }
17788 
17789  // *********************************************************************
17790  // Start communication functions
17791  // *********************************************************************
17792 
17793  //========start of get_required_elemental_information_helper==============
17794  /// \short Helper function to get the required elemental information from
17795  /// an haloed element. This info. involves the association of the element
17796  /// to a boundary or region.
17797  //========================================================================
17798  template<class ELEMENT>
17801  FiniteElement* ele_pt)
17802  {
17803  // Check if the element is associated with the original boundaries
17804  const unsigned nbound = this->initial_shared_boundary_id();
17805 
17806  // ------------------------------------------------------------------
17807  // Stores the information regarding the boundaries associated to the
17808  // element (it that is the case)
17809  Vector<unsigned> associated_boundaries;
17810  Vector<unsigned> face_index_on_boundary;
17811 
17812  unsigned counter_face_indexes = 0;
17813 
17814  for (unsigned b = 0; b < nbound; b++)
17815  {
17816  // Get the number of elements associated to boundary i
17817  const unsigned nboundary_ele = nboundary_element(b);
17818  for (unsigned e = 0; e < nboundary_ele; e++)
17819  {
17820  if (ele_pt == this->boundary_element_pt(b,e))
17821  {
17822  // Keep track of the boundaries associated to the element
17823  associated_boundaries.push_back(b);
17824  // Get the face index
17825  face_index_on_boundary.push_back(face_index_at_boundary(b,e));
17826  counter_face_indexes++;
17827 #ifdef PARANOID
17828  if (counter_face_indexes > 2)
17829  {
17830  std::stringstream error_message;
17831  error_message
17832  << "A triangular element can not have more than two of its faces "
17833  << "on a boundary!!!\n\n";
17834  throw OomphLibError(error_message.str(),
17835  OOMPH_CURRENT_FUNCTION,
17836  OOMPH_EXCEPTION_LOCATION);
17837  }
17838 #else
17839  // Already found 2 face indexes on the same boundary?
17840  if (counter_face_indexes==2) {break;}
17841 #endif // #ifdef PARANOID
17842 
17843  } // if (ele_pt == this->boundary_element_pt(b,e))
17844 
17845  } // (e < nboundary_ele)
17846 
17847  } // (b < nbound)
17848 
17849  // If the element is associated to any boundary then package all the
17850  // relevant info
17851  const unsigned nassociated_boundaries = associated_boundaries.size();
17852  if (nassociated_boundaries > 0)
17853  {
17854  Flat_packed_unsigneds.push_back(1);
17855 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17856  Flat_packed_unsigneds_string.push_back("The element is a boundary element");
17857 #endif
17858  Flat_packed_unsigneds.push_back(nassociated_boundaries);
17859 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17860  std::stringstream junk;
17861  junk << "The elements is associated to " << nassociated_boundaries << " boundaries";
17862  Flat_packed_unsigneds_string.push_back(junk.str());
17863 #endif
17864 
17865  // Package the ids of the associated boundaries and the
17866  // corresponding face index for each boundary (if the element is a
17867  // corner element, it will have two faces associated to the
17868  // boundary)
17869  for (unsigned i = 0; i < nassociated_boundaries; i++)
17870  {
17871  unsigned b = associated_boundaries[i];
17872  Flat_packed_unsigneds.push_back(b);
17873 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17874  std::stringstream junk;
17875  junk << "Element associated to boundary " << b << " of " << nassociated_boundaries << " total associated boundaries";
17876  Flat_packed_unsigneds_string.push_back(junk.str());
17877 #endif
17878  unsigned f = face_index_on_boundary[i];
17879  Flat_packed_unsigneds.push_back(f);
17880 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17881  std::stringstream junk2;
17882  junk2 << "Face index " << f << " for associated boundary " << b;
17883  Flat_packed_unsigneds_string.push_back(junk2.str());
17884 #endif
17885  }
17886 
17887  // If the element is associated to any boundary then we should
17888  // check if the mesh has regions, if that is the case then we need
17889  // to check to which region the boundary element does belong
17890 
17891  // If the mesh has regions we should look for the element
17892  // associated to a boundary and a specified region
17893  Vector<Vector<unsigned> > associated_boundaries_and_regions;
17894  Vector<unsigned> face_index_on_boundary_and_region;
17895 
17896  // Now check for the case when we have regions in the mesh
17897  const unsigned n_regions = this->nregion();
17898  if (n_regions > 1)
17899  {
17900  // Used to count the number of faces associated with
17901  // boundary-regions
17902  unsigned counter_face_indexes_in_regions = 0;
17903  // Loop over the boundaries
17904  for (unsigned b = 0; b < nbound; b++)
17905  {
17906  // Go through each region by getting the region id
17907  for (unsigned i_reg = 0 ; i_reg < n_regions; i_reg++)
17908  {
17909  // Get thre region id associated with the (i_reg)-th region
17910  const unsigned region_id =
17911  static_cast<unsigned>(this->Region_attribute[i_reg]);
17912 
17913  // Loop over all elements associated with the current boundary
17914  // and the i_reg-th region and check if the element is part of
17915  // any region
17916  const unsigned nele_in_region =
17917  this->nboundary_element_in_region(b, region_id);
17918  for (unsigned ee = 0; ee < nele_in_region; ee++)
17919  {
17920  // Check if the boundary-region element is the same as the
17921  // element
17922  if (ele_pt ==
17923  this->boundary_element_in_region_pt(b, region_id, ee))
17924  {
17925  // Storage for the boundary and region associated to the
17926  // element
17927  Vector<unsigned> bound_and_region(2);
17928 
17929  // Keep track of the boundaries associated to the element
17930  bound_and_region[0] = b;
17931  // Keep track of the regions associated to the element
17932  bound_and_region[1] = region_id;
17933  // Add the boundaries and regions in the storage to be
17934  // sent to other processors
17935  associated_boundaries_and_regions.push_back(bound_and_region);
17936  // Get the face index and keep track of it
17937  face_index_on_boundary_and_region.push_back(
17938  this->face_index_at_boundary_in_region(b,region_id,ee));
17939 
17940  // Increase the number of faces of the element associated
17941  // to boundary-regions
17942  counter_face_indexes_in_regions++;
17943 
17944 #ifdef PARANOID
17945  if (counter_face_indexes_in_regions > 2)
17946  {
17947  std::stringstream error_message;
17948  error_message
17949  << "A triangular element can not have more than two of its\n"
17950  << "faces on a boundary!!!\n\n";
17951  throw OomphLibError(error_message.str(),
17952  OOMPH_CURRENT_FUNCTION,
17953  OOMPH_EXCEPTION_LOCATION);
17954  } // if (counter_face_indexes_in_regions > 2)
17955 #endif
17956 
17957  } // The element is a boundary-region element
17958 
17959  } // for (ee < nele_in_region)
17960 
17961  } // for (i_reg < n_regions)
17962 
17963  } // for (b < nbound)
17964 
17965  } // if (n_regions > 1)
17966 
17967  // Now package the info. to be sent to other processors
17968  const unsigned nassociated_boundaries_and_regions =
17969  associated_boundaries_and_regions.size();
17970  if (nassociated_boundaries_and_regions > 0)
17971  {
17972  Flat_packed_unsigneds.push_back(1);
17973 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17974  Flat_packed_unsigneds_string.push_back("The element is associated to boundaries and regions");
17975 #endif
17976 
17977  Flat_packed_unsigneds.push_back(nassociated_boundaries_and_regions);
17978 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17979  std::stringstream junk;
17980  junk << "The element is associated to " << nassociated_boundaries_and_regions << " boundaries-regions";
17981  Flat_packed_unsigneds_string.push_back(junk.str());
17982 #endif
17983 
17984  // Package the ids of the associated boundaries, regions and the
17985  // corresponding face index for each boundary-region (if the
17986  // element is a corner element, it will have two faces
17987  // associated to the boundary-region)
17988  for (unsigned i = 0; i < nassociated_boundaries_and_regions; i++)
17989  {
17990  const unsigned b = associated_boundaries_and_regions[i][0];
17991  Flat_packed_unsigneds.push_back(b);
17992 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17993  std::stringstream junk;
17994  junk << "Element associated to boundary " << b << " of " << nassociated_boundaries_and_regions << " total associated boundaries-regions";
17995  Flat_packed_unsigneds_string.push_back(junk.str());
17996 #endif
17997 
17998  const unsigned r = associated_boundaries_and_regions[i][1];
17999  Flat_packed_unsigneds.push_back(r);
18000 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18001  std::stringstream junk2;
18002  junk2 << "Element associated to region " << r << " of " << nassociated_boundaries_and_regions << " total associated boundaries-regions";
18003  Flat_packed_unsigneds_string.push_back(junk2.str());
18004 #endif
18005 
18006  const unsigned f = face_index_on_boundary_and_region[i];
18007  Flat_packed_unsigneds.push_back(f);
18008 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18009  std::stringstream junk3;
18010  junk3 << "Face index " << f << " for associated boundary-region (" << b << "-" << r << ")";
18011  Flat_packed_unsigneds_string.push_back(junk3.str());
18012 #endif
18013  } // for (i < nassociated_boundaries_and_regions)
18014  } // if (nassociated_boundaries_and_regions > 0)
18015  else
18016  {
18017  Flat_packed_unsigneds.push_back(0);
18018 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18019  Flat_packed_unsigneds_string.push_back("The element is NOT associated to boundaries and regions");
18020 #endif
18021  } // else if (nassociated_boundaries_and_regions > 0)
18022 
18023  }
18024  else
18025  {
18026  Flat_packed_unsigneds.push_back(0);
18027 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18028  Flat_packed_unsigneds_string.push_back("The element is not associated to any original boundary");
18029 #endif
18030  }
18031 
18032  // ------------------------------------------------------------
18033  // Now review if the element is associated to a shared boundary
18034 
18035  // Store the shared boundaries, and therefore the face indexes
18036  // associated to the element
18037  Vector<unsigned> associated_shared_boundaries;
18038  Vector<unsigned> face_index_on_shared_boundary;
18039 
18040  // Get the shared boundaries in this processor
18041  Vector<unsigned> my_rank_shared_boundaries_ids;
18042  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
18043 
18044  // Get the number of shared boundaries
18045  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
18046  // Loop over the shared boundaries
18047  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
18048  {
18049  // Get the boundary id
18050  const unsigned sb = my_rank_shared_boundaries_ids[i];
18051 
18052  // Get the number of elements associated to shared boundary sb
18053  const unsigned nboundary_ele = this->nshared_boundary_element(sb);
18054  for (unsigned e = 0; e < nboundary_ele; e++)
18055  {
18056  if (ele_pt == this->shared_boundary_element_pt(sb,e))
18057  {
18058  // Keep track of the boundaries associated to the element
18059  associated_shared_boundaries.push_back(sb);
18060  // Get the face index
18061  face_index_on_shared_boundary.push_back(
18062  this->face_index_at_shared_boundary(sb, e));
18063  }
18064  } // (e < nboundary_ele)
18065  } // (i < nmy_rank_shd_bnd)
18066 
18067  // If the element is associated to a shared boundary then package
18068  // all the relevant info
18069  const unsigned nassociated_shared_boundaries =
18070  associated_shared_boundaries.size();
18071  if (nassociated_shared_boundaries > 0)
18072  {
18073  Flat_packed_unsigneds.push_back(3);
18074 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18075  Flat_packed_unsigneds_string.push_back("The element is a shared boundary element");
18076 #endif
18077  Flat_packed_unsigneds.push_back(nassociated_shared_boundaries);
18078 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18079  std::stringstream junk;
18080  junk << "The elements is associated to " << nassociated_shared_boundaries << "shared boundaries";
18081  Flat_packed_unsigneds_string.push_back(junk.str());
18082 #endif
18083 
18084  // Package the ids of the associated boundaries
18085  for (unsigned i = 0; i < nassociated_shared_boundaries; i++)
18086  {
18087  const unsigned b = associated_shared_boundaries[i];
18088  Flat_packed_unsigneds.push_back(b);
18089 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18090  std::stringstream junk;
18091  junk << "Element associated to shared boundary " << b << " of " << nassociated_shared_boundaries << " total associated boundaries";
18092  Flat_packed_unsigneds_string.push_back(junk.str());
18093 #endif
18094 
18095  const unsigned f = face_index_on_shared_boundary[i];
18096  Flat_packed_unsigneds.push_back(f);
18097 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18098  std::stringstream junk2;
18099  junk2 << "Face index " << f << " for associated shared boundary " << b;
18100  Flat_packed_unsigneds_string.push_back(junk2.str());
18101 #endif
18102  }
18103  }
18104  else
18105  {
18106  Flat_packed_unsigneds.push_back(0);
18107 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18108  Flat_packed_unsigneds_string.push_back("The element is not associated to any shared boundary");
18109 #endif
18110  }
18111 
18112  }
18113 
18114  //========start of get_required_nodal_information_helper==================
18115  /// Helper function to get the required nodal information from an
18116  /// haloed node so that a fully-functional halo node (and therefore element)
18117  /// can be created on the receiving process
18118  //========================================================================
18119  template<class ELEMENT>
18122  Node* nod_pt)
18123  {
18124  unsigned my_rank = this->communicator_pt()->my_rank();
18125  const unsigned nproc = this->communicator_pt()->nproc();
18126 
18127  // Tell the halo copy of this node how many values there are
18128  // [NB this may be different for nodes within the same element, e.g.
18129  // when using Lagrange multipliers]
18130  unsigned n_val=nod_pt->nvalue();
18131  Flat_packed_unsigneds.push_back(n_val);
18132 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18133  Flat_packed_unsigneds_string.push_back("Number of values");
18134 #endif
18135 
18136  unsigned n_dim=nod_pt->ndim();
18137 
18138  // Default number of previous values to 1
18139  unsigned n_prev=1;
18140  if (this->Time_stepper_pt!=0)
18141  {
18142  // Add number of history values to n_prev
18143  n_prev=this->Time_stepper_pt->ntstorage();
18144  }
18145 
18146  // -----------------------------------------------------
18147  // Is the node on an original boundary?
18148  // Store the original boundaries where the node may be
18149  Vector<unsigned> original_boundaries;
18150  // Loop over the original boundaries of the mesh and check if live
18151  // on one of them
18152  const unsigned n_bnd = this->initial_shared_boundary_id();
18153  for (unsigned bb=0;bb<n_bnd;bb++)
18154  {
18155  // Which boundaries (could be more than one) is it on?
18156  if (nod_pt->is_on_boundary(bb))
18157  {
18158  original_boundaries.push_back(bb);
18159  }
18160 
18161  }
18162 
18163  const unsigned n_original_boundaries = original_boundaries.size();
18164  // Is the node on any original boundary?
18165  if (n_original_boundaries > 0)
18166  {
18167  // Indicate that the node is on an original boundary
18168  Flat_packed_unsigneds.push_back(2);
18169 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18170  Flat_packed_unsigneds_string.push_back("Node is on the original boundaries");
18171 #endif
18172 
18173  Flat_packed_unsigneds.push_back(n_original_boundaries);
18174 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18175  std::stringstream junk;
18176  junk << "Node is on "<< n_original_boundaries << " original boundaries";
18177  Flat_packed_unsigneds_string.push_back(junk.str());
18178 #endif
18179 
18180  // Loop over the original boundaries the node is on
18181  for (unsigned i=0;i<n_original_boundaries;i++)
18182  {
18183  Flat_packed_unsigneds.push_back(original_boundaries[i]);
18184 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18185  std::stringstream junk;
18186  junk<<"Node is on boundary "<<original_boundaries[i]<<" of "<< nb;
18187  Flat_packed_unsigneds_string.push_back(junk.str());
18188 #endif
18189  // Get the boundary coordinate of the node
18190  Vector<double> zeta(1);
18191  nod_pt->get_coordinates_on_boundary(original_boundaries[i],zeta);
18192  Flat_packed_doubles.push_back(zeta[0]);
18193  }
18194  }
18195  else
18196  {
18197  // Indicate that the node is NOT on an original boundary
18198  Flat_packed_unsigneds.push_back(0);
18199 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18200  Flat_packed_unsigneds_string.push_back("Node is on any original boundary");
18201 #endif
18202  }
18203 
18204  // -------------------------------------------------------
18205  // Is the node on shared boundaries?
18206  bool node_on_shared_boundary = false;
18207  // Loop over the shared boundaries with the iproc processors and
18208  // check if live on one of them
18209  const unsigned n_shd_bnd = this->nshared_boundaries(my_rank, iproc);
18210  for (unsigned bb=0;bb<n_shd_bnd;bb++)
18211  {
18212  // Get the boundary id
18213  unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
18214  // Which boundaries (could be more than one) is it on?
18215  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
18216  {
18217  node_on_shared_boundary = true;
18218  break;
18219  }
18220  }
18221 
18222  // If the node live on any of the shared boundaries with the iproc
18223  // processor then just get the node number according to the
18224  // sorted_shared_boundary_node_pt() scheme and send it accross
18225  if (node_on_shared_boundary)
18226  {
18227  Flat_packed_unsigneds.push_back(1);
18228 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18229  Flat_packed_unsigneds_string.push_back("Node is on shared boundary");
18230 #endif
18231 
18232  // Store the shared boundaries where the node is on
18233  Vector<unsigned> shd_boundaries;
18234  // Loop over the shared boundaries with the iproc processor
18235  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
18236  {
18237  // Get the boundary id
18238  const unsigned i_bnd =
18239  this->shared_boundaries_ids(my_rank, iproc, bb);
18240  // Which boundaries (could be more than one) is it on?
18241  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
18242  {
18243  shd_boundaries.push_back(i_bnd);
18244  }
18245  }
18246 
18247  // Get the number of shared boundaries the node is on
18248  const unsigned n_shd_bnd_is_on = shd_boundaries.size();
18249  // Send the number of shared boundaries the node is on
18250  Flat_packed_unsigneds.push_back(n_shd_bnd_is_on);
18251 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18252  std::stringstream junk;
18253  junk << "Node is on "<< n_shd_bnd_is_on << " shared boundaries";
18254  Flat_packed_unsigneds_string.push_back(junk.str());
18255 #endif
18256 
18257  // Loop over the shared boundaries to send their ids
18258  for (unsigned i=0;i<n_shd_bnd_is_on;i++)
18259  {
18260  Flat_packed_unsigneds.push_back(shd_boundaries[i]);
18261 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18262  std::stringstream junk;
18263  junk << "Node is on boundary " << shd_boundaries[i] << " of " << nb;
18264  Flat_packed_unsigneds_string.push_back(junk.str());
18265 #endif
18266  }
18267 
18268  // Given that the node is on at least one boundary get the index
18269  // of the node in one of the boundaries and send this index
18270  unsigned shared_boundary_id = shd_boundaries[0];
18271  // Get the number of nodes on the given shared boundary
18272  const unsigned n_nodes_on_shared_boundary =
18273  nsorted_shared_boundary_node(shared_boundary_id);
18274  // Store the index of the node on the shared boundary
18275  unsigned index_node_on_shared_boundary;
18276 #ifdef PARANOID
18277  // Flag to know if the node has been found
18278  bool found_index_node_on_shared_boundary = false;
18279 #endif
18280  // Loop over the nodes on the shared boundary to find the node
18281  for (unsigned i = 0; i < n_nodes_on_shared_boundary; i++)
18282  {
18283  // Get the i-th node on the shared boundary
18284  Node* shared_node_pt =
18285  sorted_shared_boundary_node_pt(shared_boundary_id, i);
18286  // Is the node we are looking for
18287  if (shared_node_pt == nod_pt)
18288  {
18289  // Store the index
18290  index_node_on_shared_boundary = i;
18291 #ifdef PARANOID
18292  // Mark as found
18293  found_index_node_on_shared_boundary = true;
18294 #endif
18295  break; // break
18296  }
18297 
18298  } // for (i < nnodes_on_shared_boundary)
18299 
18300 #ifdef PARANOID
18301  if (!found_index_node_on_shared_boundary)
18302  {
18303  std::ostringstream error_message;
18304  error_message
18305  <<"The index of the node on boundary ("
18306  <<shared_boundary_id<<") was not found.\n"
18307  <<"The node coordinates are ("<<nod_pt->x(0)<<","
18308  <<nod_pt->x(1)<<").\n";
18309  throw OomphLibError(
18310  error_message.str(),
18311  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18312  OOMPH_EXCEPTION_LOCATION);
18313  }
18314 #endif
18315  // Send the index of the node on the shared boundary
18316  Flat_packed_unsigneds.push_back(index_node_on_shared_boundary);
18317 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18318  std::stringstream junk2;
18319  junk2 << "Node index on boundary "<<boundaries[0]<<" is "
18320  <<index_node_on_shared_boundary;
18321  Flat_packed_unsigneds_string.push_back(junk2.str());
18322 #endif
18323 
18324  } // if (node_on_shared_boundary)
18325  else
18326  {
18327  // The node is not on a shared boundary
18328  Flat_packed_unsigneds.push_back(0);
18329 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18330  Flat_packed_unsigneds_string.push_back("Node is not on a shared boundary");
18331 #endif
18332  }
18333 
18334  // ----------------------------------------------------------------
18335  // Is the node on any shared boundary where the receiver processor
18336  // is not involved?
18337 
18338  // Now check if the node is on a shared boundary created by the
18339  // current processor (my_rank) and other processor different that
18340  // the iproc processor. This info. will help to complete the sending
18341  // of halo(ed) information between processors
18342 
18343  // Flag to know if the node is on a shared boundary with other
18344  // processor
18345  bool node_on_shared_boundary_with_other_processors = false;
18346  // Count the number of other shared boundaries it could be on
18347  unsigned nshared_boundaries_with_other_processors_have_node = 0;
18348 
18349  // Loop over the shared boundaries of the sent processor (my_rank)
18350  // and other processors (jproc)
18351  for (unsigned jproc = 0; jproc < nproc; jproc++)
18352  {
18353  // Do not search with the iproc processor , that was done before
18354  // above because we are sending info to that processor
18355  if (jproc != iproc)
18356  {
18357  // Get the number of shared boundaries with the jproc processor
18358  const unsigned n_jshd_bnd =
18359  this->nshared_boundaries(my_rank, jproc);
18360  // Loop over the shared boundaries
18361  for (unsigned bb=0;bb<n_jshd_bnd;bb++)
18362  {
18363  // Get the boundary id
18364  const unsigned j_shd_bnd =
18365  this->shared_boundaries_ids(my_rank, jproc, bb);
18366  // Is the node part of this boundary?
18367  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
18368  {
18369 // DEBP("Sending to");
18370 // DEBP(iproc);
18371 // DEBP("Pair of procs where other shared");
18372 // DEBP(my_rank);
18373 // DEBP(jproc);
18374 // DEBP(i_bnd);
18375  node_on_shared_boundary_with_other_processors = true;
18376  // Increase the counter for the number of shared boundaries
18377  // with other processors the node is on
18378  nshared_boundaries_with_other_processors_have_node++;
18379  } // if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt)
18380 
18381  } // for (bb<n_jshd_bnd)
18382 
18383  } // if (jproc != iproc)
18384 
18385  } // for (jproc < nproc)
18386 
18387  // If the node is on a shared boundary with another processor
18388  // (my_rank, jproc), then send the flag and look for the info.
18389  if (node_on_shared_boundary_with_other_processors)
18390  {
18391  Flat_packed_unsigneds.push_back(4);
18392 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18393  Flat_packed_unsigneds_string.push_back("Node is on shared boundary no related with the received processor: 4");
18394 #endif
18395 
18396  // The number of packages of information that will be sent to the
18397  // "iproc" processor. This helps to know how many packages of data
18398  // read from the received processor
18399  Flat_packed_unsigneds.push_back(nshared_boundaries_with_other_processors_have_node);
18400 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18401  std::stringstream junk;
18402  junk << "Number of other shared boundaries that the node is on: "
18403  << nshared_boundaries_with_other_processors_have_node;
18404  Flat_packed_unsigneds_string.push_back(junk.str());
18405 #endif
18406 
18407  // Counter to ensure that the correct number of data has been sent
18408  unsigned counter_shd_bnd_with_other_procs_have_node = 0;
18409  // Loop over the shared boundaries with other processors and get:
18410  // 1) The processors defining the shared boundary
18411  // 2) The shared boundary id
18412  // 3) The index of the node on the shared boundary
18413  Vector<unsigned> other_processor_1;
18414  Vector<unsigned> other_processor_2;
18415  Vector<unsigned> shd_bnd_ids;
18416  Vector<unsigned> indexes;
18417  // Loop over the processors again
18418  for (unsigned jproc = 0; jproc < nproc; jproc++)
18419  {
18420  // Do not search with the iproc processor, that was done before
18421  // above
18422  if (jproc != iproc)
18423  {
18424  // Get the number of shared boundaries with the jproc
18425  // processor
18426  const unsigned n_jshd_bnd =
18427  this->nshared_boundaries(my_rank, jproc);
18428  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
18429  {
18430  // Get the boundary id
18431  const unsigned j_shd_bnd =
18432  this->shared_boundaries_ids(my_rank, jproc, bb);
18433  // Is the node part of this boundary?
18434  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
18435  {
18436  // Include the first processor
18437  other_processor_1.push_back(my_rank);
18438  // Include the second processor
18439  other_processor_2.push_back(jproc);
18440  // Include the shared boundary id
18441  shd_bnd_ids.push_back(j_shd_bnd);
18442  // Increase the counter for found shared boundaries with
18443  // other processors
18444  counter_shd_bnd_with_other_procs_have_node++;
18445  }
18446 
18447  } // for (bb < nshared_bnd)
18448 
18449  } // if (jproc != iproc)
18450 
18451  } // for (jproc < nproc)
18452 
18453  // Get the indexes of the node on all the shared boundaries where
18454  // it was found
18455  const unsigned n_other_processors = other_processor_1.size();
18456  // Loop over the processors where the node was found
18457  for (unsigned i = 0; i < n_other_processors; i++)
18458  {
18459  // Get the shared boundary id
18460  unsigned shd_bnd_id = shd_bnd_ids[i];
18461  // Get the number of nodes on that shared boundary
18462  const unsigned n_nodes_on_shd_bnd =
18463  nsorted_shared_boundary_node(shd_bnd_id);
18464 
18465 #ifdef PARANOID
18466  bool found_index_node_on_shared_boundary = false;
18467 #endif
18468  for (unsigned i = 0; i < n_nodes_on_shd_bnd; i++)
18469  {
18470  // Get the i-th shared boundary node
18471  Node* shared_node_pt =
18472  sorted_shared_boundary_node_pt(shd_bnd_id, i);
18473  // Is the same node?
18474  if (shared_node_pt == nod_pt)
18475  {
18476 // DEBP(i_node);
18477 // DEBP(nod_pt->x(0));
18478 // DEBP(nod_pt->x(1));
18479  // Include the index of the node
18480  indexes.push_back(i);
18481 #ifdef PARANOID
18482  // Mark as found the node
18483  found_index_node_on_shared_boundary = true;
18484 #endif
18485  break;
18486  } // if (shared_node_pt == nod_pt)
18487 
18488  } // for (i < n_nodes_on_shd_bnd)
18489 
18490 #ifdef PARANOID
18491  if (!found_index_node_on_shared_boundary)
18492  {
18493  std::ostringstream error_message;
18494  error_message
18495  <<"The index of the node on boundary ("
18496  <<shd_bnd_id<<"), shared by other processors\nwas not found.\n"
18497  <<"The node coordinates are ("<<nod_pt->x(0)<<","
18498  <<nod_pt->x(1)<<").\n";
18499  throw OomphLibError(
18500  error_message.str(),
18501  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18502  OOMPH_EXCEPTION_LOCATION);
18503  }
18504 #endif
18505  } // for (i < n_other_processors)
18506 
18507  // Now send the info. but first check that the number of found
18508  // nodes be the same that the previously found shared boundaries
18509  // with the node
18510 #ifdef PARANOID
18511  if (counter_shd_bnd_with_other_procs_have_node !=
18512  nshared_boundaries_with_other_processors_have_node)
18513  {
18514  std::ostringstream error_message;
18515  error_message
18516  <<"The number of shared boundaries where the node is on "
18517  <<"is different:\n"
18518  << "nshared_boundaries_with_other_processors_have_node: ("
18519  << nshared_boundaries_with_other_processors_have_node
18520  << ")\n"
18521  << "counter_shd_bnd_with_other_procs_have_node: ("
18522  << counter_shd_bnd_with_other_procs_have_node
18523  << ")\n";
18524  throw OomphLibError(
18525  error_message.str(),
18526  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18527  OOMPH_EXCEPTION_LOCATION);
18528  } // if (counter_shd_bnd_with_other_procs_have_node !=
18529  // nshared_boundaries_with_other_processors_have_node)
18530 #endif
18531 
18532  // Loop over the info. to send it
18533  for (unsigned i = 0; i < n_other_processors; i++)
18534  {
18535  Flat_packed_unsigneds.push_back(other_processor_1[i]);
18536 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18537  std::stringstream junk1;
18538  junk1 << "Processor where the other shared boundary "
18539  << "has the node: " << other_processor_1[i];
18540  Flat_packed_unsigneds_string.push_back(junk1.str());
18541 #endif
18542 
18543  Flat_packed_unsigneds.push_back(other_processor_2[i]);
18544 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18545  std::stringstream junk2;
18546  junk2 << "Processor where the other shared boundary "
18547  << "has the node: " << other_processor_2[i];
18548  Flat_packed_unsigneds_string.push_back(junk2.str());
18549 #endif
18550 
18551  Flat_packed_unsigneds.push_back(shd_bnd_ids[i]);
18552 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18553  std::stringstream junk3;
18554  junk3 << "Other shared boundary id where the node is on"
18555  << boundaries[i];
18556  Flat_packed_unsigneds_string.push_back(junk3.str());
18557 #endif
18558 
18559  Flat_packed_unsigneds.push_back(indexes[i]);
18560 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18561  std::stringstream junk4;
18562  junk4 << "Node index on other shared boundary "
18563  <<boundaries[i] << " is "
18564  << indexes[i];
18565  Flat_packed_unsigneds_string.push_back(junk4.str());
18566 #endif
18567 
18568  } // for (i < n_other_processors)
18569 
18570  } // if (node_on_shared_boundary_with_other_processors)
18571  else
18572  {
18573  Flat_packed_unsigneds.push_back(0);
18574 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18575  Flat_packed_unsigneds_string.push_back("Node is on any shared boundary with other processors");
18576 #endif
18577  } // else if (node_on_shared_boundary_with_other_processors)
18578 
18579  // Now check if it is required to send the info. of the node. If the
18580  // node is not on a shared boundary with the iproc processor then we
18581  // need to send the info.
18582 
18583  if (!node_on_shared_boundary)
18584  {
18585  // Send all the info. to create it
18586 
18587  // Is the Node algebraic? If so, send its ref values and
18588  // an indication of its geometric objects if they are stored
18589  // in the algebraic mesh
18590  AlgebraicNode* alg_nod_pt=dynamic_cast<AlgebraicNode*>(nod_pt);
18591  if (alg_nod_pt!=0)
18592  {
18593  // The external mesh should be algebraic
18594  AlgebraicMesh* alg_mesh_pt=dynamic_cast<AlgebraicMesh*>(this);
18595 
18596  // Get default node update function ID
18597  unsigned update_id=alg_nod_pt->node_update_fct_id();
18598  Flat_packed_unsigneds.push_back(update_id);
18599 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18600  Flat_packed_unsigneds_string.push_back("Alg Node update id");
18601 #endif
18602 
18603  // Get reference values at default...
18604  unsigned n_ref_val=alg_nod_pt->nref_value();
18605  Flat_packed_unsigneds.push_back(n_ref_val);
18606 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18607  Flat_packed_unsigneds_string.push_back("Alg Node n ref values");
18608 #endif
18609  for (unsigned i_ref_val=0;i_ref_val<n_ref_val;i_ref_val++)
18610  {
18611  Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
18612  }
18613 
18614  // Access geometric objects at default...
18615  unsigned n_geom_obj=alg_nod_pt->ngeom_object();
18616  Flat_packed_unsigneds.push_back(n_geom_obj);
18617 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18618  Flat_packed_unsigneds_string.push_back("Alg Node n geom objects");
18619 #endif
18620  for (unsigned i_geom=0;i_geom<n_geom_obj;i_geom++)
18621  {
18622  GeomObject* geom_obj_pt=alg_nod_pt->geom_object_pt(i_geom);
18623 
18624  // Check this against the stored geometric objects in mesh
18625  unsigned n_geom_list=alg_mesh_pt->ngeom_object_list_pt();
18626 
18627  // Default found index to zero
18628  unsigned found_geom_object=0;
18629  for (unsigned i_list=0;i_list<n_geom_list;i_list++)
18630  {
18631  if (geom_obj_pt==alg_mesh_pt->geom_object_list_pt(i_list))
18632  {
18633  found_geom_object=i_list;
18634  }
18635  }
18636  Flat_packed_unsigneds.push_back(found_geom_object);
18637 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18638  Flat_packed_unsigneds_string.push_back("Found geom object");
18639 #endif
18640  }
18641  } // (if alg_nod_pt!=0)
18642 
18643  // Is it a SolidNode?
18644  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(nod_pt);
18645  if (solid_nod_pt!=0)
18646  {
18647  unsigned n_solid_val=solid_nod_pt->variable_position_pt()->nvalue();
18648  for (unsigned i_val=0;i_val<n_solid_val;i_val++)
18649  {
18650  for (unsigned t=0;t<n_prev;t++)
18651  {
18652  Flat_packed_doubles.push_back(solid_nod_pt->variable_position_pt()->
18653  value(t,i_val));
18654  }
18655  }
18656 
18657  Vector<double> values_solid_node;
18658  solid_nod_pt->add_values_to_vector(values_solid_node);
18659  const unsigned nvalues_solid_node = values_solid_node.size();
18660  Flat_packed_unsigneds.push_back(nvalues_solid_node);
18661 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18662  std::stringstream junk;
18663  junk << "Number of values solid node: "
18664  << nvalues_solid_node;
18665  Flat_packed_unsigneds_string.push_back(junk.str());
18666 #endif
18667  for (unsigned i = 0; i < nvalues_solid_node; i++)
18668  {
18669  Flat_packed_doubles.push_back(values_solid_node[i]);
18670  }
18671  }
18672 
18673  // Finally copy info required for all node types
18674  for (unsigned i_val=0;i_val<n_val;i_val++)
18675  {
18676  for (unsigned t=0;t<n_prev;t++)
18677  {
18678  Flat_packed_doubles.push_back(nod_pt->value(t,i_val));
18679  }
18680  }
18681 
18682  // Now do positions
18683  for (unsigned idim=0;idim<n_dim;idim++)
18684  {
18685  for (unsigned t=0;t<n_prev;t++)
18686  {
18687  Flat_packed_doubles.push_back(nod_pt->x(t,idim));
18688  }
18689  }
18690 
18691  } // if (!node_on_shared_boundary)
18692 
18693  }
18694 
18695  //==========start of add_haloed_node_helper===============================
18696  /// Helper to add external haloed node that is not a master
18697  //========================================================================
18698  template<class ELEMENT>
18700  add_haloed_node_helper(unsigned& iproc, Node* nod_pt)
18701  {
18702  // Attempt to add this node as a haloed node
18703  const unsigned n_haloed_nod = this->nhaloed_node(iproc);
18704  const unsigned haloed_node_index =
18705  this->try_to_add_haloed_node_pt(iproc,nod_pt);
18706 
18707  // If it was added then the new index should match the size of the storage
18708  if (haloed_node_index==n_haloed_nod)
18709  {
18710  Flat_packed_unsigneds.push_back(1);
18711 
18712 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18713  std::stringstream junk;
18714  junk << "Node needs to be constructed [size="
18715  << Flat_packed_unsigneds.size() << "]; last entry: "
18717  Flat_packed_unsigneds_string.push_back(junk.str());
18718 #endif
18719 
18720  // This helper function gets all the required information for the
18721  // specified node and stores it into MPI-sendable information
18722  // so that a halo copy can be made on the receiving process
18724  }
18725  else // It was already added
18726  {
18727  Flat_packed_unsigneds.push_back(0);
18728 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18729  std::stringstream junk;
18730  junk << "Node was already added [size="
18731  << Flat_packed_unsigneds.size() << "]; last entry: "
18733 
18734  Flat_packed_unsigneds_string.push_back(junk.str());
18735 #endif
18736 
18737  // This node is already a haloed node, so tell
18738  // the other process its index in the equivalent halo storage
18739  Flat_packed_unsigneds.push_back(haloed_node_index);
18740 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18741  Flat_packed_unsigneds_string.push_back("haloed node index");
18742 #endif
18743  }
18744 
18745  }
18746 
18747  //================= send_and_receive_haloed_info =======================
18748  /// Send the information of the elements that will be created on the other
18749  /// processor
18750  //======================================================================
18751  template<class ELEMENT>
18753  send_and_receive_elements_nodes_info(int &send_proc, int &recv_proc)
18754  {
18755  // Get the communicator of the mesh
18756  OomphCommunicator* comm_pt = this->communicator_pt();
18757 
18758  // Set MPI info
18759  MPI_Status status;
18760  MPI_Request request;
18761 
18762  // Prepare vectors to receive information
18763  Vector<double> received_double_values;
18764  Vector<unsigned> received_unsigned_values;
18765 
18766  // Send the double values associated with halo(ed) elements and nodes
18767  //-------------------------------------------------------------------
18768  unsigned send_count_double_values=Flat_packed_doubles.size();
18769  MPI_Isend(&send_count_double_values,1,MPI_UNSIGNED,
18770  send_proc,1,comm_pt->mpi_comm(),&request);
18771 
18772  int receive_count_double_values=0;
18773  MPI_Recv(&receive_count_double_values,1,MPI_INT,
18774  recv_proc,1,comm_pt->mpi_comm(),&status);
18775  MPI_Wait(&request,MPI_STATUS_IGNORE);
18776 
18777  if (send_count_double_values!=0)
18778  {
18779  MPI_Isend(&Flat_packed_doubles[0],send_count_double_values,MPI_DOUBLE,
18780  send_proc,2,comm_pt->mpi_comm(),&request);
18781  }
18782  if (receive_count_double_values!=0)
18783  {
18784  received_double_values.resize(receive_count_double_values);
18785  MPI_Recv(&received_double_values[0],receive_count_double_values,
18786  MPI_DOUBLE,recv_proc,2,comm_pt->mpi_comm(),&status);
18787  }
18788  if (send_count_double_values!=0)
18789  {
18790  MPI_Wait(&request,MPI_STATUS_IGNORE);
18791  }
18792 
18793  // Now send unsigned values associated with halo(ed) elements and nodes
18794  //---------------------------------------------------------------------
18795  unsigned send_count_unsigned_values=Flat_packed_unsigneds.size();
18796 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18797  unsigned send_count_unsigned_string=Flat_packed_unsigneds_string.size();
18798 #ifdef PARANOID
18799  if (send_count_unsigned_string != send_count_unsigned_values)
18800  {
18801  std::ostringstream error_message;
18802  error_message
18803  << "The number of unsigned values to send to processor ("
18804  << send_proc << ") is different from the\nnumber of annotated strings "
18805  << "for the communication\n\n";
18806  throw OomphLibError(error_message.str(),
18807  OOMPH_CURRENT_FUNCTION,
18808  OOMPH_EXCEPTION_LOCATION);
18809  }
18810 #endif // #ifdef PARANOID
18811 #endif
18812  MPI_Isend(&send_count_unsigned_values,1,MPI_UNSIGNED,
18813  send_proc,14,comm_pt->mpi_comm(),&request);
18814 
18815  int receive_count_unsigned_values=0;
18816  MPI_Recv(&receive_count_unsigned_values,1,MPI_INT,recv_proc,14,
18817  comm_pt->mpi_comm(),&status);
18818 
18819  MPI_Wait(&request,MPI_STATUS_IGNORE);
18820 
18821  if (send_count_unsigned_values!=0)
18822  {
18823  MPI_Isend(&Flat_packed_unsigneds[0],send_count_unsigned_values,
18824  MPI_UNSIGNED,send_proc,15,comm_pt->mpi_comm(),&request);
18825 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18826  for (unsigned i=0;i<send_count_unsigned_values;i++)
18827  {
18828  oomph_info << "Sent:" << i << " to orig_proc:" << send_proc
18829  << " " << Flat_packed_unsigneds_string[i]
18830  << ": " << Flat_packed_unsigneds[i] << std::endl;
18831  }
18832 #endif
18833  }
18834  if (receive_count_unsigned_values!=0)
18835  {
18836  received_unsigned_values.resize(receive_count_unsigned_values);
18837  MPI_Recv(&received_unsigned_values[0],receive_count_unsigned_values,
18838  MPI_UNSIGNED,recv_proc,15,comm_pt->mpi_comm(),&status);
18839  }
18840 
18841  if (send_count_unsigned_values!=0)
18842  {
18843  MPI_Wait(&request,MPI_STATUS_IGNORE);
18844  }
18845 
18846  // Copy across into original containers -- these can now
18847  //------------------------------------------------------
18848  // be processed by create_external_halo_elements() to generate
18849  //------------------------------------------------------------
18850  // external halo elements
18851  //------------------------
18852  Flat_packed_doubles.resize(receive_count_double_values);
18853  for (int ii=0;ii<receive_count_double_values;ii++)
18854  {
18855  Flat_packed_doubles[ii]=received_double_values[ii];
18856  }
18857  Flat_packed_unsigneds.resize(receive_count_unsigned_values);
18858  for (int ii=0;ii<receive_count_unsigned_values;ii++)
18859  {
18860  Flat_packed_unsigneds[ii]=received_unsigned_values[ii];
18861  }
18862 
18863  }
18864 
18865  //=====================================================================
18866  /// Creates (halo) element on the loop process based on the
18867  /// information received from each processor
18868  //=====================================================================
18869  template<class ELEMENT>
18871  create_halo_element(unsigned& iproc,
18872  Vector<Node*> &new_nodes_on_domain,
18873  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
18874  &other_proc_shd_bnd_node_pt,
18876  &global_node_names,
18877  std::map<Vector<unsigned>, unsigned>
18878  &node_name_to_global_index,
18879  Vector<Node*> &global_shared_node_pt)
18880  {
18881 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18883  << " Bool: New element needs to be constructed "
18885  << std::endl;
18886 #endif
18887 
18889  {
18890  // Create a new element from the communicated values
18891  // and coords from the process that located zeta
18892  GeneralisedElement *new_el_pt= new ELEMENT;
18893 
18894  // Add the element, it is a new element in the mesh
18895  this->add_element_pt(new_el_pt);
18896 
18897  // Add halo element to this mesh
18898  this->add_root_halo_element_pt(iproc, new_el_pt);
18899 
18900  // Cast to the FE pointer
18901  FiniteElement* f_el_pt=dynamic_cast<FiniteElement*>(new_el_pt);
18902 
18903  // Check if new element is associated to any boundary
18904  this->add_halo_element_helper(iproc,f_el_pt);
18905 
18906  // Now we add nodes to the new element
18907  unsigned n_node=f_el_pt->nnode();
18908 
18909  for (unsigned j=0;j<n_node;j++)
18910  {
18911  Node* new_nod_pt=0;
18912 
18913  // Call the add halo node helper function
18914  add_halo_node_helper(new_nod_pt,
18915  new_nodes_on_domain,
18916  other_proc_shd_bnd_node_pt,
18917  iproc, j, f_el_pt,
18918  global_node_names,
18919  node_name_to_global_index,
18920  global_shared_node_pt);
18921 
18922  } // for (j<n_nod)
18923 
18924  }
18925  else // the element already exists as halo
18926  {
18927 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18928  oomph_info
18929  << "Rec:" << Counter_for_flat_packed_unsigneds
18930  << " Index of existing halo element "
18932  << std::endl;
18933 #endif
18934  // The index itself is in Flat_packed_unsigneds[...]
18935  unsigned halo_ele_index=
18937 
18938  // Use this index to get the element
18939  FiniteElement* f_el_pt=
18940  dynamic_cast<FiniteElement*>(this->root_halo_element_pt(iproc,
18941  halo_ele_index));
18942 
18943  //If it's not a finite element die
18944  if(f_el_pt==0)
18945  {
18946  throw OomphLibError("Halo element is not a FiniteElement\n",
18947  OOMPH_CURRENT_FUNCTION,
18948  OOMPH_EXCEPTION_LOCATION);
18949  }
18950 
18951  } // else the element already exists as halo
18952 
18953  }
18954 
18955  //========start of add_halo_element_helper==============================
18956  /// \short Helper function to create (halo) elements on the loop
18957  /// process based on the info received in send_and_received_located_info
18958  /// This function is in charge of verify if the element is associated to
18959  /// a boundary
18960  //======================================================================
18961  template<class ELEMENT>
18963  add_halo_element_helper(unsigned& iproc, FiniteElement* ele_pt)
18964  {
18965 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18967  << " Bool: Element is associated to an original boundary "
18969  << std::endl;
18970 #endif
18971 
18973  {
18974 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18975  oomph_info
18976  << "Rec:" << Counter_for_flat_packed_unsigneds
18977  << " How many boundaries are associated with the element "
18979  << std::endl;
18980 #endif
18981  const unsigned nassociated_boundaries =
18983 
18984  for (unsigned b = 0; b < nassociated_boundaries; b++)
18985  {
18986 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18987  oomph_info
18988  << "Rec:" << Counter_for_flat_packed_unsigneds
18989  << " Boundary associated to the element "
18991  << std::endl;
18992 #endif
18993  const unsigned bnd =
18995 
18996 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18997  oomph_info
18998  << "Rec:" << Counter_for_flat_packed_unsigneds
18999  << " Face index of the element "
19001  << std::endl;
19002 #endif
19003  const unsigned face_index =
19005 
19006  // Associate the element with the boundary and establish as many
19007  // face indexes it has
19008  this->Boundary_element_pt[bnd].push_back(ele_pt);
19009  this->Face_index_at_boundary[bnd].push_back(face_index);
19010 
19011  } // (b < nassociated_boundaries)
19012 
19013  // Here read the info. regarding the boundary-region of the element
19014 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19016  << " Bool: Element is associated to a boundary-region "
19018  << std::endl;
19019 #endif
19020 
19022  {
19023 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19024  oomph_info
19025  << "Rec:" << Counter_for_flat_packed_unsigneds
19026  << " How many boundaries-regions are associated with the element "
19028  << std::endl;
19029 #endif
19030  const unsigned nassociated_boundaries_and_regions =
19032 
19033  for (unsigned br = 0; br < nassociated_boundaries_and_regions; br++)
19034  {
19035 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19036  oomph_info
19037  << "Rec:" << Counter_for_flat_packed_unsigneds
19038  << " Boundary associated to the element "
19040  << std::endl;
19041 #endif
19042  const unsigned bnd =
19044 
19045 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19046  oomph_info
19047  << "Rec:" << Counter_for_flat_packed_unsigneds
19048  << " Region associated to the element "
19050  << std::endl;
19051 #endif
19052  const unsigned region =
19054 
19055 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19056  oomph_info
19057  << "Rec:" << Counter_for_flat_packed_unsigneds
19058  << " Face index of the element in boundary-region "
19060  << std::endl;
19061 #endif
19062  const unsigned face_index =
19064 
19065  // Associate the element with the boundary-regions and establish
19066  // as many face indexes it has
19067  this->Boundary_region_element_pt[bnd][region].push_back(ele_pt);
19068  this->Face_index_region_at_boundary[bnd][region].push_back(face_index);
19069 
19070  } // for (br < nassociated_boundaries_and_regions)
19071 
19072  } // Is the element associated with a boundary-region?
19073 
19074  }
19075 
19076  // Now check if the element is associated to a shared boundary
19077 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19079  << " Bool: Element is associated to a shared boundary "
19081  << std::endl;
19082 #endif
19084  {
19085 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19086  oomph_info
19087  << "Rec:" << Counter_for_flat_packed_unsigneds
19088  << " How many shared boundaries are associated with the element "
19090  << std::endl;
19091 #endif
19092  const unsigned nassociated_shared_boundaries =
19094 
19095  for (unsigned b = 0; b < nassociated_shared_boundaries; b++)
19096  {
19097 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19098  oomph_info
19099  << "Rec:" << Counter_for_flat_packed_unsigneds
19100  << " Shared boundary associated to the element "
19102  << std::endl;
19103 #endif
19104  const unsigned bnd =
19106 
19107 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19108  oomph_info
19109  << "Rec:" << Counter_for_flat_packed_unsigneds
19110  << " Face index of the element associated to the shared boundary "
19112  << std::endl;
19113 #endif
19114 
19115  const unsigned face_index =
19117 
19118  this->add_shared_boundary_element(bnd, ele_pt);
19119  this->add_face_index_at_shared_boundary(bnd, face_index);
19120 
19121  } // (b < nassociated_shared_boundaries)
19122 
19123  } // The element is associted with a shared boundary
19124 
19125  }
19126 
19127  //========start of add_halo_node_helper==========================
19128  /// Helper function to add halo node
19129  //===============================================================
19130  template<class ELEMENT>
19132  (Node* &new_nod_pt,
19133  Vector<Node*> &new_nodes_on_domain,
19134  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
19135  &other_proc_shd_bnd_node_pt,
19136  unsigned& iproc,
19137  unsigned& node_index,
19138  FiniteElement* const &new_el_pt,
19139  Vector<Vector<Vector<unsigned> > > &global_node_names,
19140  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
19141  Vector<Node*> &global_shared_node_pt)
19142  {
19143  // Given the node, received information about them from process
19144  // iproc, construct them on the current process
19145 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19147  << " Bool: New node needs to be constructed "
19149  << std::endl;
19150 #endif
19152  {
19153  // Construct a new node based upon sent information, or copy a node
19154  // from one of the shared boundaries
19155  construct_new_halo_node_helper(new_nod_pt, new_nodes_on_domain,
19156  other_proc_shd_bnd_node_pt,
19157  iproc, node_index, new_el_pt,
19158  global_node_names,
19159  node_name_to_global_index,
19160  global_shared_node_pt);
19161  }
19162  else
19163  {
19164 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19166  << " Index of existing halo node "
19168  << std::endl;
19169 #endif
19170 
19171  // Copy node from received location
19172  new_nod_pt = new_nodes_on_domain[
19174 
19175  new_el_pt->node_pt(node_index)=new_nod_pt;
19176 
19177  }
19178 
19179  }
19180 
19181  //========start of construct_new_halo_node_helper=================
19182  //Helper function which constructs a new external halo node (on new element)
19183  //with the required information sent from the haloed process
19184  //========================================================================
19185  template<class ELEMENT>
19187  (Node* &new_nod_pt,
19188  Vector<Node*> &new_nodes_on_domain,
19189  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
19190  &other_proc_shd_bnd_node_pt,
19191  unsigned& iproc, unsigned& node_index,
19192  FiniteElement* const &new_el_pt,
19193  Vector<Vector<Vector<unsigned> > > &global_node_names,
19194  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
19195  Vector<Node*> &global_shared_node_pt)
19196  {
19197  //The first entry indicates the number of values at this new Node
19198  //(which may be different across the same element e.g. Lagrange multipliers)
19199 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19201  << " Number of values of external halo node "
19203  << std::endl;
19204 #endif
19206 
19207  // Null TimeStepper for now
19208  TimeStepper* time_stepper_pt=this->Time_stepper_pt;
19209  // Default number of previous values to 1
19210  unsigned n_prev=time_stepper_pt->ntstorage();
19211 
19212  // ------------------------------------------------------
19213  // Check if the node is on an original boundary
19214 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19216  << " Is the node on an original boundary "
19218  << std::endl;
19219 #endif
19220 
19221  // Flag to indicate if the node is on original boundaries
19222  const unsigned node_on_original_boundaries =
19224 
19225  // Store the original boundaries where the node is on
19226  Vector<unsigned> original_boundaries_node_is_on;
19227  // Store the zeta coordinates of the node on the original boundaries
19228  Vector<double> zeta_coordinates;
19229  // Store the number of original boundaries the node is on
19230  unsigned n_original_boundaries_node_is_on = 0;
19231 
19232  if (node_on_original_boundaries==2)
19233  {
19234  // How many original boundaries does the node live on?
19235 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19237  << " Number of boundaries the node is on: "
19239  << std::endl;
19240 #endif
19241  n_original_boundaries_node_is_on =
19243 
19244  // Resize the containers
19245  original_boundaries_node_is_on.resize(n_original_boundaries_node_is_on);
19246  zeta_coordinates.resize(n_original_boundaries_node_is_on);
19247 
19248  for (unsigned i=0;i<n_original_boundaries_node_is_on;i++)
19249  {
19250  // Boundary number
19251 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19253  << " Node is on boundary "
19255  << std::endl;
19256 #endif
19257  original_boundaries_node_is_on[i] =
19259  zeta_coordinates[i] =
19261  }
19262 
19263  } // if (node_on_original_boundaries==2)
19264 #ifdef PARANOID
19265  else
19266  {
19267  if (node_on_original_boundaries != 0)
19268  {
19269  std::ostringstream error_message;
19270  error_message
19271  <<"The current node is not on an original boundary, this should\n"
19272  <<"be indicated by a zero flag. However, the read value for\n"
19273  <<"that flag is ("<<node_on_original_boundaries<<").\n\n";
19274  throw OomphLibError(
19275  error_message.str(),
19276  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19277  OOMPH_EXCEPTION_LOCATION);
19278  } // if (node_on_original_boundaries != 0)
19279  }
19280 #endif
19281 
19282  // --------------------------------------------------------------
19283  // Check if the node was on a shared boundary with the iproc
19284  // processor
19285 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19287  << " Is node on shared boundary? "
19289  << std::endl;
19290 #endif
19291  const unsigned is_node_on_shared_boundary =
19293  if (is_node_on_shared_boundary == 1)
19294  {
19295  // How many shared boundaries does the node live on?
19296 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19298  << " Number of boundaries the node is on: "
19300  << std::endl;
19301 #endif
19302  const unsigned n_shd_bnd_node_is_on =
19304  Vector<unsigned> shd_bnds_node_is_on(n_shd_bnd_node_is_on);
19305  for (unsigned i=0;i<n_shd_bnd_node_is_on;i++)
19306  {
19307  // Shared boundary number
19308 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19310  << " Node is on boundary "
19312  << std::endl;
19313 #endif
19314  shd_bnds_node_is_on[i] =
19316  }
19317 
19318  // Get the index of the node on the shared boundary
19319 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19321  << " Index of node on boundary "
19323  << std::endl;
19324 #endif
19325  // Get the node index of the node on the shared boundary
19326  unsigned node_index_on_shared_boundary =
19328 
19329  // Get the pointer to the node with the received info.
19330  new_nod_pt =
19331  this->sorted_shared_boundary_node_pt(shd_bnds_node_is_on[0],
19332  node_index_on_shared_boundary);
19333 
19334  } // if (is_node_on_shared_boundary == 1)
19335 #ifdef PARANOID
19336  else
19337  {
19338  if (is_node_on_shared_boundary != 0)
19339  {
19340  std::ostringstream error_message;
19341  error_message
19342  <<"The current node is not on a shared boundary, this should\n"
19343  <<"be indicated by a zero flag. However, the read value for\n"
19344  <<"that flag is ("<<is_node_on_shared_boundary<<").\n\n";
19345  throw OomphLibError(
19346  error_message.str(),
19347  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19348  OOMPH_EXCEPTION_LOCATION);
19349  } // if (node_on_shared_boundary != 0)
19350  }
19351 #endif
19352 
19353  // ------------------------------------------------------------
19354  // Is the node on a shared boundary with other processor?
19355 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19357  << " Is the node on shared boundaries with other processors "
19359  << std::endl;
19360 #endif
19361 
19362  // Is the node in shared boundaries no associated with the
19363  // receiver processor
19364  const unsigned is_the_node_in_shared_boundaries_with_other_processors =
19366 
19367  // The containers where to store the info.
19368  Vector<unsigned> other_processor_1;
19369  Vector<unsigned> other_processor_2;
19370  Vector<unsigned> other_shared_boundaries;
19371  Vector<unsigned> other_indexes;
19372 
19373  // How many shared bounaries with other processors the node lives on
19374  unsigned n_shd_bnd_with_other_procs_have_node = 0;
19375 
19376  // Is the node on shared boundaries with other processors
19377  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19378  {
19379 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19381  << " In how many shared boundaries with other "
19382  << "processors is the node "
19384  << std::endl;
19385 #endif
19386 
19387  // How many nodes on other shared boundaries were found
19388  n_shd_bnd_with_other_procs_have_node =
19390 
19391  // Resize the containers
19392  other_processor_1.resize(n_shd_bnd_with_other_procs_have_node);
19393  other_processor_2.resize(n_shd_bnd_with_other_procs_have_node);
19394  other_shared_boundaries.resize(n_shd_bnd_with_other_procs_have_node);
19395  other_indexes.resize(n_shd_bnd_with_other_procs_have_node);
19396 
19397  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
19398  {
19399 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19401  << " Processor where the other shared boundary"
19402  << "has the node"
19404  << std::endl;
19405 #endif
19406  // Read the other processor 1
19407  other_processor_1[i] =
19409 
19410 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19412  << " Processor where the other shared boundary"
19413  << "has the node"
19415  << std::endl;
19416 #endif
19417  // Read the other processor 2
19418  other_processor_2[i] =
19420 
19421 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19423  << " Other shared boundary id where the node is on: "
19425  << std::endl;
19426 #endif
19427 
19428  // Read the other shared boundary id
19429  other_shared_boundaries[i] =
19431 
19432 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19434  << " Node index on the other shared boundary "
19436  << std::endl;
19437 #endif
19438 
19439  // Read the node index on the other shared boundary
19440  other_indexes[i] =
19442 
19443  } // for (i < n_shd_bnd_with_other_procs_have_node)
19444 
19445  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19446 #ifdef PARANOID
19447  else
19448  {
19449  if (is_the_node_in_shared_boundaries_with_other_processors != 0)
19450  {
19451  std::ostringstream error_message;
19452  error_message
19453  <<"The current node is not on a shared boundary with\n"
19454  <<"other processors, this should be indicated by a zero flag.\n"
19455  <<"However, the read value for that flag is ("
19456  <<is_the_node_in_shared_boundaries_with_other_processors<<").\n\n";
19457  throw OomphLibError(
19458  error_message.str(),
19459  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19460  OOMPH_EXCEPTION_LOCATION);
19461  }
19462  }
19463 #endif
19464 
19465  // Now we have all the info. to decide whether the node should be
19466  // created or not
19467 
19468  // First check if the node is a shared boundary node
19469  if (is_node_on_shared_boundary == 1)
19470  {
19471  // We already have the node, we do not need to create it
19472 
19473  // Only check if we need to add boundary info. to the node
19474  if (node_on_original_boundaries==2)
19475  {
19476  // The node is a boundary node, add the boundary info. before
19477  // adding it to the domain
19478 
19479  // Associate the node to the given boundaries
19480  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
19481  {
19482  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
19483  // Establish the boundary coordinates for the node
19484  Vector<double> zeta(1);
19485  zeta[0] = zeta_coordinates[i];
19486  new_nod_pt->set_coordinates_on_boundary(
19487  original_boundaries_node_is_on[i],zeta);
19488  }
19489 
19490  } // if (node_on_original_boundaries==2)
19491 
19492  // Add the node to the domain
19493  new_nodes_on_domain.push_back(new_nod_pt);
19494 
19495  // Add the node to the element
19496  new_el_pt->node_pt(node_index) = new_nod_pt;
19497 
19498  } // if (is_node_on_shared_boundary == 1)
19499 
19500  // Now check if the node is on a shared boundary with another
19501  // processor, if that is the case try to find the node that may have
19502  // been already sent by the other processors
19503 
19504  // This flags indicates if the node was found, and then decide if it
19505  // is required to create the node
19506  bool found_node_in_other_shared_boundaries = false;
19507  // Flag to indicate whether the node should be created as a boundary
19508  // node or not. If the node lies on a shared boundary with other
19509  // processor the we create it as a boundary node. The processor from
19510  // which we are receiving info. (iproc) may not know that the node
19511  // lies on an original boundary. If the node lies on an original
19512  // boundary then its info. will be sent by another processor, then
19513  // we can set its boundary info. since the node was constructed as a
19514  // boundary node
19515  bool build_node_as_boundary_node = false;
19516 
19517  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19518  {
19519  // Build the node as a boundary node
19520  build_node_as_boundary_node = true;
19521 
19522  // Try to get the node pointer in case that the node has been
19523  // already sent by the other processors
19524 
19525  // Get the number of initial shared boundaries to correct the
19526  // index of the shared boundary
19527  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
19528 
19529  // Add the found nodes in the container
19530  Vector<Node*> found_node_pt;
19531 
19532  // Now try to find the node in any of the other shared boundaries
19533  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
19534  {
19535  // We always check with the lower processor number. The
19536  // info. is only stored in one direction. More importantly,
19537  // this is done with the hope that the info. has been already
19538  // received from the other processor given that its info. was
19539  // processed before the current processor (iproc). NOTE that
19540  // it is not always the case that this info. has been received
19541  // from the other processors since it may have not require to
19542  // send the elements (and nodes) on the shared boundary with
19543  // the current processor (iproc).
19544  unsigned oproc1 = other_processor_1[i];
19545  unsigned oproc2 = other_processor_2[i];
19546  if (other_processor_1[i] > other_processor_2[i])
19547  {
19548  oproc1 = other_processor_2[i];
19549  oproc2 = other_processor_1[i];
19550  } // if (other_processor_1[i] > other_processor_2[i])
19551 
19552  // Re-compute the shared boundary id between the other
19553  // processors
19554  const unsigned shd_bnd_id =
19555  other_shared_boundaries[i] - initial_shd_bnd_id;
19556 
19557  // Read the index
19558  const unsigned index = other_indexes[i];
19559 
19560  // Check if there are nodes received from the other processor
19561  // and with the given shared boundary
19562  const unsigned n_nodes_on_other_processor =
19563  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].size();
19564 
19565  if (n_nodes_on_other_processor > 0)
19566  {
19567  // Check if we can find the index of the node in that
19568  // other processor and shared boundary id
19569  std::map<unsigned, Node*>::iterator it =
19570  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].
19571  find(index);
19572 
19573  // If the index exist then get the node pointer
19574  if (it!=
19575  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
19576  {
19577  // Mark the node as found
19578  found_node_in_other_shared_boundaries = true;
19579  // Get the node pointer
19580  Node* tmp_node_pt = (*it).second;
19581 
19582  // Push back the node pointer
19583  found_node_pt.push_back(tmp_node_pt);
19584 
19585  } // if (it!=
19586  // other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
19587 
19588  } // if (n_nodes_on_other_processor > 0)
19589 
19590  } // for (i < n_shd_bnd_with_other_procs_have_node)
19591 
19592  // If the node was found, then all their instances should be the
19593  // same but better check
19594  if (found_node_in_other_shared_boundaries)
19595  {
19596 #ifdef PARANOID
19597  const unsigned n_times_node_found = found_node_pt.size();
19598  for (unsigned j = 1; j < n_times_node_found; j++)
19599  {
19600  if (found_node_pt[j-1] != found_node_pt[j])
19601  {
19602  std::ostringstream error_message;
19603  error_message
19604  <<"The instances of the node that was found on\n"
19605  <<"shared boundaries with other processors (but not\n"
19606  <<"on shared boundaries with this processor) are not\n"
19607  <<"the same.\n"
19608  <<"These are the coordinates of the instances of the\n"
19609  <<"nodes:\n"
19610  <<"(" << found_node_pt[j-1]->x(0) << ", "
19611  << found_node_pt[j-1]->x(1) << ")\n"
19612  <<"(" << found_node_pt[j]->x(0) << ", "
19613  << found_node_pt[j]->x(1) << ")\n"
19614  <<"Dont be surprised if they are the same since the "
19615  << "node is\nrepeated.\n";
19616  throw OomphLibError(error_message.str(),
19617  OOMPH_CURRENT_FUNCTION,
19618  OOMPH_EXCEPTION_LOCATION);
19619 
19620  } // if (found_node_pt[j-1] != found_node_pt[j])
19621 
19622  } // for (j < ntimes_node_found)
19623 #endif // #ifdef PARANOID
19624 
19625  // Check if the node is a shared boundary node from the
19626  // current processor and the iproc processor, if that is the
19627  // case, and the node is also on a shared boundary with other
19628  // processor, then the pointer should be the same!!!
19629  if (is_node_on_shared_boundary == 1)
19630  {
19631  //const unsigned n_times_node_found = found_node_pt.size();
19632  // The pointer to the node is already assigned, it was
19633  // assigned when the node was found to be on a shared
19634  // boundary with the sending processor (iproc). Check that
19635  // any previous instances of the node have been copied
19636  // from the shared boundary, if that is not the case then
19637  // there is a problem
19638  if (found_node_pt[0] != new_nod_pt)
19639  {
19640  std::ostringstream error_message;
19641  error_message
19642  <<"The pointer of the node that was found to be on a\n"
19643  <<"shared boundary with other processor(s) and the pointer\n"
19644  <<"of the node on shared boundary with the receiver\n"
19645  <<"processor (iproc) are not the same. This means we have a\n"
19646  << "repeated node)\n"
19647  <<"The coordinates for the nodes are:\n"
19648  <<"(" << found_node_pt[0]->x(0) << ", "
19649  << found_node_pt[0]->x(1) << ")\n"
19650  <<"(" << new_nod_pt->x(0) << ", "
19651  << new_nod_pt->x(1) << ")\n"
19652  <<"Dont be surprised if they are the same since the "
19653  << "node is\nrepeated.\n";
19654  throw OomphLibError(error_message.str(),
19655  OOMPH_CURRENT_FUNCTION,
19656  OOMPH_EXCEPTION_LOCATION);
19657 
19658  } // if (found_node_pt[i] != new_nod_pt)
19659 
19660  } // if (is_node_on_shared_boundary == 1)
19661  else
19662  {
19663  // Take the first instance of the node in case that it was
19664  // found and is not on a shared boundary with the iproc
19665  // processor (the processor from which we are receiving
19666  // the info.)
19667  new_nod_pt = found_node_pt[0];
19668 
19669  }
19670 
19671  } // if (found_node_in_other_shared_boundaries)
19672 
19673  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19674 
19675  // -----------------------------------------------------------------
19676  // Create the node or read the received info if the node is not on a
19677  // shared boundary with the iproc processor
19678  if (is_node_on_shared_boundary != 1)
19679  {
19680  // If the node is on a shared boundary with other processor we
19681  // need to read all the info. since the processor that sent the
19682  // info. did not know that the node is part of another shared
19683  // boundary
19684 
19685  // If the node is not on a shared boundary (with any processor),
19686  // or if this is the first time that the info. of the node is
19687  // received from any of the processors with which it has a shared
19688  // boundary, then we create the node
19689 
19690  // Is the node a boundary node or should it be build as a boundary
19691  // node because it is on a shared boundary with other processors
19692  if (node_on_original_boundaries==2 || build_node_as_boundary_node)
19693  {
19694  // Check if necessary to create the node, or if it has been
19695  // already found in shared boundaries with other processors
19696  if (!found_node_in_other_shared_boundaries)
19697  {
19698  // Construct a boundary node
19699  if (time_stepper_pt!=0)
19700  {
19701  new_nod_pt=new_el_pt->construct_boundary_node(node_index,
19702  time_stepper_pt);
19703  }
19704  else
19705  {
19706  new_nod_pt=new_el_pt->construct_boundary_node(node_index);
19707  }
19708 
19709  } // if (!found_node_in_other_shared_boundaries)
19710  else
19711  {
19712  // If the node was found then assign the node to the element
19713  new_el_pt->node_pt(node_index) = new_nod_pt;
19714 
19715  } // else if (!found_node_in_other_shared_boundaries)
19716 
19717  // Associate the node to the given boundaries
19718  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
19719  {
19720  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
19721  // Establish the boundary coordinates for the node
19722  Vector<double> zeta(1);
19723  zeta[0] = zeta_coordinates[i];
19724  new_nod_pt->set_coordinates_on_boundary(
19725  original_boundaries_node_is_on[i],zeta);
19726  }
19727 
19728  } // if (node is on an original boundary)
19729  else
19730  {
19731  // Check if necessary to create the node, or if it has been
19732  // already found in shared boundaries with other processors
19733  if (!found_node_in_other_shared_boundaries)
19734  {
19735  // Construct an ordinary (non-boundary) node
19736  if (time_stepper_pt!=0)
19737  {
19738  new_nod_pt=new_el_pt->construct_node(node_index, time_stepper_pt);
19739  }
19740  else
19741  {
19742  new_nod_pt=new_el_pt->construct_node(node_index);
19743  }
19744  } // if (!found_node_in_other_shared_boundaries)
19745  else
19746  {
19747  // If the node was found then assign the node to the element
19748  new_el_pt->node_pt(node_index) = new_nod_pt;
19749  } // else if (!found_node_in_other_shared_boundaries)
19750 
19751  } // else (the node is not a boundary node)
19752 
19753  // ... and gather all its information
19754 
19755  // If the node was found or not in other shared boundaries, this
19756  // is the first time the node is received from this processor
19757  // (iproc), therefore it is added to the vector of nodes received
19758  // from this processor (iproc)
19759  new_nodes_on_domain.push_back(new_nod_pt);
19760 
19761  // Check if necessary to state all the info. to the node if it has
19762  // been already found in shared boundaries with other processors
19763  if (!found_node_in_other_shared_boundaries)
19764  {
19765  // Add the node to the general node storage
19766  this->add_node_pt(new_nod_pt);
19767  } // if (!found_node_in_other_shared_boundaries)
19768 
19769  // Is the new constructed node Algebraic?
19770  AlgebraicNode* new_alg_nod_pt=dynamic_cast<AlgebraicNode*>
19771  (new_nod_pt);
19772 
19773  // If it is algebraic, its node update functions will
19774  // not yet have been set up properly
19775  if (new_alg_nod_pt!=0)
19776  {
19777  // The AlgebraicMesh is the external mesh
19778  AlgebraicMesh* alg_mesh_pt=dynamic_cast<AlgebraicMesh*>(this);
19779 
19780  /// The first entry of All_alg_nodal_info contains
19781  /// the default node update id
19782  /// e.g. for the quarter circle there are
19783  /// "Upper_left_box", "Lower right box" etc...
19784 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19786  << " Alg node update id "
19788  << std::endl;
19789 #endif
19790 
19791  unsigned update_id=Flat_packed_unsigneds
19793 
19794  Vector<double> ref_value;
19795 
19796  // The size of this vector is in the next entry
19797  // of All_alg_nodal_info
19798 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19800  << " Alg node # of ref values "
19802  << std::endl;
19803 #endif
19804  unsigned n_ref_val=Flat_packed_unsigneds
19806 
19807  // The reference values themselves are in
19808  // All_alg_ref_value
19809  ref_value.resize(n_ref_val);
19810  for (unsigned i_ref=0;i_ref<n_ref_val;i_ref++)
19811  {
19812  ref_value[i_ref]=Flat_packed_doubles
19814  }
19815 
19816  Vector<GeomObject*> geom_object_pt;
19817  /// again we need the size of this vector as it varies
19818  /// between meshes; we also need some indication
19819  /// as to which geometric object should be used...
19820 
19821  // The size of this vector is in the next entry
19822  // of All_alg_nodal_info
19823 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19825  << " Alg node # of geom objects "
19827  << std::endl;
19828 #endif
19829  unsigned n_geom_obj=Flat_packed_unsigneds
19831 
19832  // The remaining indices are in the rest of
19833  // All_alg_nodal_info
19834  geom_object_pt.resize(n_geom_obj);
19835  for (unsigned i_geom=0;i_geom<n_geom_obj;i_geom++)
19836  {
19837 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19839  << " Alg node: geom object index "
19841  << std::endl;
19842 #endif
19843  unsigned geom_index=Flat_packed_unsigneds
19845  // This index indicates which of the AlgebraicMesh's
19846  // stored geometric objects should be used
19847  // (0 is a null pointer; everything else should have
19848  // been filled in by the specific Mesh). If it
19849  // hasn't been filled in then the update_node_update
19850  // call should fix it
19851  geom_object_pt[i_geom]=alg_mesh_pt->
19852  geom_object_list_pt(geom_index);
19853  }
19854 
19855  // Check if necessary to state all the info. to the node if it has
19856  // been already found in shared boundaries with other processors
19857  if (!found_node_in_other_shared_boundaries)
19858  {
19859  /// For the received update_id, ref_value, geom_object
19860  /// call add_node_update_info
19861  new_alg_nod_pt->add_node_update_info
19862  (update_id,alg_mesh_pt,geom_object_pt,ref_value);
19863 
19864  /// Now call update_node_update
19865  alg_mesh_pt->update_node_update(new_alg_nod_pt);
19866 
19867  } // if (!found_node_in_other_shared_boundaries)
19868 
19869  } // if (new_alg_nod_pt!=0)
19870 
19871  // Check if necessary to state all the info. to the node if it has
19872  // been already found in shared boundaries with other processors
19873  if (!found_node_in_other_shared_boundaries)
19874  {
19875  // Is the node a MacroElementNodeUpdateNode?
19876  MacroElementNodeUpdateNode* macro_nod_pt=
19877  dynamic_cast<MacroElementNodeUpdateNode*>(new_nod_pt);
19878 
19879  if (macro_nod_pt!=0)
19880  {
19881  // Need to call set_node_update_info; this requires
19882  // a Vector<GeomObject*> (taken from the mesh)
19883  Vector<GeomObject*> geom_object_vector_pt;
19884 
19885  // Access the required geom objects from the
19886  // MacroElementNodeUpdateMesh
19887  MacroElementNodeUpdateMesh* macro_mesh_pt=
19888  dynamic_cast<MacroElementNodeUpdateMesh*>(this);
19889  geom_object_vector_pt=
19890  macro_mesh_pt->geom_object_vector_pt();
19891 
19892  // Get local coordinate of node in new element
19893  Vector<double> s_in_macro_node_update_element;
19894  new_el_pt->local_coordinate_of_node
19895  (node_index,s_in_macro_node_update_element);
19896 
19897  // Set node update info for this node
19898  macro_nod_pt->set_node_update_info
19899  (new_el_pt,s_in_macro_node_update_element,
19900  geom_object_vector_pt);
19901  }
19902 
19903  } // if (!found_node_in_other_shared_boundaries)
19904 
19905  // If there are additional values, resize the node
19906  unsigned n_new_val=new_nod_pt->nvalue();
19907 
19908  // Check if necessary to state all the info. to the node if it has
19909  // been already found in shared boundaries with other processors
19910  if (!found_node_in_other_shared_boundaries)
19911  {
19912  if (n_val>n_new_val)
19913  {
19914  // If it has been necessary to resize then it may be becuse
19915  // the node is on a FSI boundary, if that is the case we need
19916  // to set a map for these external values
19917 
19918  // Cast to a boundary node
19919  BoundaryNodeBase *bnod_pt =
19920  dynamic_cast<BoundaryNodeBase*>(new_nod_pt);
19921 
19922  // Create storage, if it doesn't already exist, for the map
19923  // that will contain the position of the first entry of
19924  // this face element's additional values,
19926  {
19928  new std::map<unsigned, unsigned>;
19929  }
19930 
19931  // Get pointer to the map
19932  std::map<unsigned, unsigned>* map_pt=
19934 
19935  // The id of the face to which this node belong in the bulk
19936  // element
19937  const unsigned id_face = 0;
19938  // We only resize the node values Vector if we haven't done it yet
19939  std::map<unsigned, unsigned>::const_iterator p=map_pt->find(id_face);
19940 
19941  // If this node hasn't been resized for current id
19942  if(p==map_pt->end())
19943  {
19944  // assign the face element id and the position of the
19945  //first entry to the boundary node
19946  (*map_pt)[id_face] = n_new_val;
19947 
19948  // resize the node vector of values
19949  new_nod_pt->resize(n_val);
19950  }
19951 
19952  } // if (n_val>n_new_val)
19953 
19954  } // if (!found_node_in_other_shared_boundaries)
19955 
19956  // Is the new node a SolidNode?
19957  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(new_nod_pt);
19958  if (solid_nod_pt!=0)
19959  {
19960  unsigned n_solid_val=solid_nod_pt->variable_position_pt()->nvalue();
19961  for (unsigned i_val=0;i_val<n_solid_val;i_val++)
19962  {
19963  for (unsigned t=0;t<n_prev;t++)
19964  {
19965  double read_data =
19967 
19968  // Check if necessary to state all the info. to the node if it has
19969  // been already found in shared boundaries with other processors
19970  if (!found_node_in_other_shared_boundaries)
19971  {
19972  solid_nod_pt->variable_position_pt()->
19973  set_value(t, i_val, read_data);
19974  } // if (!found_node_in_other_shared_boundaries)
19975 
19976  }
19977 
19978  }
19979 
19980 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19982  << " Number of values solid node: "
19984  << std::endl;
19985 #endif
19986  const unsigned nvalues_solid_node =
19988  Vector<double> values_solid_node(nvalues_solid_node);
19989  for (unsigned i = 0; i < nvalues_solid_node; i++)
19990  {
19991  values_solid_node[i] =
19993  }
19994 
19995  // Check if necessary to state all the info. to the node if it has
19996  // been already found in shared boundaries with other processors
19997  if (!found_node_in_other_shared_boundaries)
19998  {
19999  unsigned index = 0;
20000  solid_nod_pt->read_values_from_vector(values_solid_node, index);
20001  }
20002 
20003  }
20004 
20005  // Get copied history values
20006  // unsigned n_val=new_nod_pt->nvalue();
20007  for (unsigned i_val=0;i_val<n_val;i_val++)
20008  {
20009  for (unsigned t=0;t<n_prev;t++)
20010  {
20011  double read_data =
20013 
20014  // Check if necessary to state all the info. to the node if it
20015  // has been already found in shared boundaries with other
20016  // processors
20017  if (!found_node_in_other_shared_boundaries)
20018  {
20019  new_nod_pt->set_value(t, i_val, read_data);
20020  } // if (!found_node_in_other_shared_boundaries)
20021 
20022  }
20023 
20024  }
20025 
20026  // Get copied history values for positions
20027  unsigned n_dim=new_nod_pt->ndim();
20028  for (unsigned idim=0;idim<n_dim;idim++)
20029  {
20030  for (unsigned t=0;t<n_prev;t++)
20031  {
20032  double read_data =
20034 
20035  // Check if necessary to state all the info. to the node if it
20036  // has been already found in shared boundaries with other
20037  // processors
20038  if (!found_node_in_other_shared_boundaries)
20039  {
20040  // Copy to coordinate
20041  new_nod_pt->x(t,idim) = read_data;
20042 
20043  } // if (!found_node_in_other_shared_boundaries)
20044  }
20045  }
20046 
20047  } // if (is_node_on_shared_boundary != 1)
20048 
20049  // If the node was not found in other shared boundaries (possibly
20050  // because it is the first time the node has been sent) then copy
20051  // the node to the shared boundaries where it should be, use the
20052  // special container for this cases
20053  if (n_shd_bnd_with_other_procs_have_node > 0 && // The node is on
20054  // shared
20055  // boundaries with
20056  // other processors
20057  !found_node_in_other_shared_boundaries) // The node has not
20058  // been previously
20059  // set as
20060  // shared with
20061  // other processors
20062  // (first time)
20063  {
20064  // Update the node pointer in all the (references) of the node
20065  this->update_other_proc_shd_bnd_node_helper(new_nod_pt,
20066  other_proc_shd_bnd_node_pt,
20067  other_processor_1,
20068  other_processor_2,
20069  other_shared_boundaries,
20070  other_indexes,
20071  global_node_names,
20072  node_name_to_global_index,
20073  global_shared_node_pt);
20074 
20075  } // if (!found_node_in_other_shared_boundaries)
20076 
20077  }
20078 
20079 //========start of update_other_proc_shd_bnd_node_helper=================
20080 //Helper function that assigns/updates the references to the node so
20081 //that it can be found with any other reference
20082 //========================================================================
20083 template<class ELEMENT>
20086 (Node* &new_node_pt,
20087  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
20088  &other_proc_shd_bnd_node_pt,
20089  Vector<unsigned> &other_processor_1,
20090  Vector<unsigned> &other_processor_2,
20091  Vector<unsigned> &other_shared_boundaries,
20092  Vector<unsigned> &other_indexes,
20093  Vector<Vector<Vector<unsigned> > > &global_node_names,
20094  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
20095  Vector<Node*> &global_shared_node_pt)
20096 {
20097  // Get the number of initial shared boundaries to correct the index
20098  // of the shared boundary
20099  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
20100 
20101 #ifdef PARANOID
20102  // Get the number of instances of the node on other shared
20103  // boundaries with other processors
20104  const unsigned n_data = other_processor_1.size();
20105 #endif // #ifdef PARANOID
20106 
20107  // Create the first node name
20108  Vector<unsigned> node_name(4);
20109  node_name[0] = other_processor_1[0];
20110  node_name[1] = other_processor_2[0];
20111  node_name[2] = other_shared_boundaries[0];
20112  node_name[3] = other_indexes[0];
20113 
20114 #ifdef PARANOID
20115  // Get the global node index, and all the names of the node
20116  std::map<Vector<unsigned>, unsigned>::iterator it =
20117  node_name_to_global_index.find(node_name);
20118  if (it==node_name_to_global_index.end())
20119  {
20120  std::ostringstream error_stream;
20121  error_stream
20122  <<"The node name does not exist in the global node names\n"
20123  <<"This is the name of the node\n"
20124  << "Name: iproc, jproc, ishd_bnd, idx\n"
20125  <<"Name: " << node_name[0] <<", " << node_name[1] <<", "
20126  << node_name[2] <<", " << node_name[3] <<"\n";
20127  throw OomphLibError(error_stream.str(),
20128  OOMPH_CURRENT_FUNCTION,
20129  OOMPH_EXCEPTION_LOCATION);
20130  } // if (it!=node_name_to_global_index.end())
20131 #endif // #ifdef PARANOID
20132 
20133  // Get the global node index
20134  const unsigned iglobal_node = node_name_to_global_index[node_name];
20135  // Add the node to the global shared node container
20136  global_shared_node_pt[iglobal_node] = new_node_pt;
20137  // Get the names
20138  Vector<Vector<unsigned> > inode_names = global_node_names[iglobal_node];
20139  // Get the number of names of the node
20140  const unsigned n_names = inode_names.size();
20141 
20142 #ifdef PARANOID
20143  // Check that the received names of the node are part of the global
20144  // node names
20145  unsigned n_found_node_names_on_global_node_name = 0;
20146  // loop over the input node names
20147  for (unsigned j = 0; j < n_data; j++)
20148  {
20149  // loop over the inode_names
20150  for (unsigned k = 0; k < n_names; k++)
20151  {
20152  // Is this input name part of the global node names?
20153  if (inode_names[k][0] == other_processor_1[j] &&
20154  inode_names[k][1] == other_processor_2[j] &&
20155  inode_names[k][2] == other_shared_boundaries[j] &&
20156  inode_names[k][3] == other_indexes[j])
20157  {
20158  // Increase the number of found input node names in the
20159  // global node names
20160  n_found_node_names_on_global_node_name++;
20161  }
20162 
20163  } // for (k < n_names)
20164 
20165  } // for (j < n_data)
20166 
20167  // Were all the input node names found on the global node names?
20168  if (n_found_node_names_on_global_node_name != n_data)
20169  {
20170  std::ostringstream error_stream;
20171  error_stream
20172  <<"Not all the node names of the current node were found on the\n"
20173  <<"global node names. This happened when adding the node pointer\n"
20174  <<"to the data structure that keeps tracks of nodes on shared\n"
20175  <<"boundaries with other processors\n\n"
20176  << "These are the names of the current node\n"
20177  << "Name k: iproc, jproc, ishd_bnd, idx\n";
20178  for (unsigned j = 0; j < n_data; j++)
20179  {
20180  error_stream<<"Name("<<j<<"): "
20181  <<other_processor_1[j] <<", "
20182  <<other_processor_2[j] <<", "
20183  <<other_shared_boundaries[j] <<", "
20184  <<other_indexes[j] <<"\n";
20185  }
20186 
20187  error_stream
20188  << "\n\nThese are the names of the global node\n"
20189  << "Name k: iproc, jproc, ishd_bnd, idx\n";
20190  for (unsigned k = 0; k < n_names; k++)
20191  {
20192  error_stream<<"Name("<<k<<"): "
20193  <<inode_names[k][0] <<", "
20194  <<inode_names[k][1] <<", "
20195  <<inode_names[k][2] <<", "
20196  <<inode_names[k][3] <<"\n";
20197  }
20198 
20199  throw OomphLibError(error_stream.str(),
20200  OOMPH_CURRENT_FUNCTION,
20201  OOMPH_EXCEPTION_LOCATION);
20202  }
20203 #endif // #ifdef PARANOID
20204 
20205  // Set the node pointer in all of its names
20206  for (unsigned j = 0; j < n_names; j++)
20207  {
20208  // Get the j-th node name
20209  const unsigned iproc = inode_names[j][0];
20210  const unsigned jproc = inode_names[j][1];
20211  const unsigned ishd_bnd = inode_names[j][2] - initial_shd_bnd_id;
20212  const unsigned index = inode_names[j][3];
20213 
20214  // The info. is stored only in one direction
20215  // Get the smallest processor number
20216  if (iproc < jproc)
20217  {
20218  other_proc_shd_bnd_node_pt[iproc][jproc][ishd_bnd][index]
20219  = new_node_pt;
20220  }
20221  else
20222  {
20223  other_proc_shd_bnd_node_pt[jproc][iproc][ishd_bnd][index]
20224  = new_node_pt;
20225  }
20226 
20227  } // for (j < n_names)
20228 
20229 }
20230 
20231  // *********************************************************************
20232  // End communication functions
20233  // *********************************************************************
20234 
20235  // *********************************************************************
20236  // BEGIN: Methods to perform load balance
20237  // *********************************************************************
20238 
20239  //======================================================================
20240  /// \short Performs the load balancing for unstructured meshes, the
20241  /// load balancing strategy is based on mesh migration
20242  //======================================================================
20243  template <class ELEMENT>
20246  target_domain_for_local_non_halo_element)
20247  {
20248  oomph_info << "Load balance (unstructured mesh) [BEGIN]" << std::endl;
20249 
20250  // This method can only be called when the mesh has been already
20251  // distributed
20252  if (!this->is_mesh_distributed())
20253  {
20254  std::ostringstream warning_message;
20255  warning_message
20256  << "\n===============================================================\n"
20257  << "The load balancing can only be performed in distributed meshes,\n"
20258  << "your mesh has not been distributed.\n"
20259  << "===============================================================\n\n";
20260  OomphLibWarning(warning_message.str(),
20261  OOMPH_CURRENT_FUNCTION,
20262  OOMPH_EXCEPTION_LOCATION);
20263  // Return
20264  return;
20265  }
20266 
20267  // Get the number of processors
20268  const unsigned nproc = this->communicator_pt()->nproc();
20269  // Get the rank of the current processors
20270  const unsigned my_rank = this->communicator_pt()->my_rank();
20271 
20272  // Check that there are at least two processors
20273  if (nproc == 1)
20274  {
20275  std::ostringstream warning_message;
20276  warning_message
20277  << "\n===============================================================\n"
20278  << "The load balancing can only be performed when there are at least\n"
20279  << "two procesors, the current number of processors is one.\n"
20280  << "===============================================================\n\n";
20281  OomphLibWarning(warning_message.str(),
20282  OOMPH_CURRENT_FUNCTION,
20283  OOMPH_EXCEPTION_LOCATION);
20284  // Return
20285  return;
20286  }
20287 
20288  // Get the time before load balance
20289  double t_start_overall_load_balance=0.0;
20290  if (Print_timings_level_load_balance>1)
20291  {
20292  t_start_overall_load_balance=TimingHelpers::timer();
20293  }
20294 
20295  // Get the number of elements in the mesh before load balance
20296  const unsigned nelement_before_load_balance = this->nelement();
20297 
20298 #ifdef PARANOID
20299  // The number of elements in the mesh and the number of target
20300  // domains for the local non halo elements in the mesh should match
20301  if (nnon_halo_element() !=
20302  target_domain_for_local_non_halo_element.size())
20303  {
20304  std::ostringstream error_message;
20305  error_message
20306  << "The number of non halo elements in the current mesh ("
20307  << nnon_halo_element() << ") and the number\n"
20308  << "of target areas for the local non halo elements ("
20309  << target_domain_for_local_non_halo_element.size()
20310  << ") is different\n\n";
20311  throw OomphLibError(error_message.str(),
20312  OOMPH_CURRENT_FUNCTION,
20313  OOMPH_EXCEPTION_LOCATION);
20314  }
20315 #endif
20316 
20317  // Backup pointers to elements in this mesh
20318  Vector<FiniteElement*> backed_up_ele_pt(nelement_before_load_balance);
20319  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20320  {
20321  backed_up_ele_pt[e] = this->finite_element_pt(e);
20322  }
20323 
20324  // =====================================================================
20325  // BEGIN: GET THE DOMAINS FOR THE HALO ELEMENTS
20326  // =====================================================================
20327 
20328  // Get the time to get the domains of halo elements
20329  double tt_start_get_domains_halo_elements=0.0;
20330  if (Print_timings_level_load_balance>1)
20331  {
20332  tt_start_get_domains_halo_elements=TimingHelpers::timer();
20333  }
20334 
20335  // Get the new domains for the halo elements
20336 
20337  // Send the new domains for the current haloed elements, and receive
20338  // the new domains for the current halo elements
20339  // -- 1) On the current processor get the new domains for the
20340  // haloed elements
20341  // -- 2) Then send this info. to all the processor that have a
20342  // halo copy of the element
20343 
20344  // The storing for the new domains of the haloed elements (sent to
20345  // other processors)
20346  Vector<Vector<unsigned> > new_domains_haloed_elements(nproc);
20347  // The storing for the new domains of the halo elements (received
20348  // from other processors)
20349  Vector<Vector<unsigned> > new_domains_halo_elements(nproc);
20350 
20351  // First resize the containers by getting the current number of
20352  // halo/haloed elements within each processor
20353  for (unsigned iproc = 0; iproc < nproc; iproc++)
20354  {
20355  // There are no halo/haloed elements with myself (my_rank
20356  // processor)
20357  if (iproc != my_rank)
20358  {
20359  // Get the number of halo elements with iproc processor
20360  const unsigned n_halo_iproc = this->nroot_halo_element(iproc);
20361  // Resize the container
20362  new_domains_halo_elements[iproc].resize(n_halo_iproc);
20363 
20364  // Get the number of haloed elements with iproc processor
20365  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20366  // Resize the container
20367  new_domains_haloed_elements[iproc].resize(n_haloed_iproc);
20368  } // if (iproc != my_rank)
20369  } // for (iproc < nproc)
20370 
20371 #ifdef PARANOID
20372  // Count the number of found haloed elements
20373  Vector<unsigned> counter_for_found_haloed_elements(nproc, 0);
20374 #endif
20375 
20376  // Go through all the haloed elements and find their new domain
20377 
20378  // Get the haloed elements with in each processor and check if the
20379  // element is haloed with the processor
20380  for (unsigned iproc = 0; iproc < nproc; iproc++)
20381  {
20382  // There are no halo/haloed elements with myself (my_rank
20383  // processor)
20384  if (iproc != my_rank)
20385  {
20386  // Get the number of haloed elements with iproc processor
20387  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20388 
20389  // Loop over the haloed elements
20390  for (unsigned ihd = 0; ihd < n_haloed_iproc; ihd++)
20391  {
20392  // Get the ihd-th haloed element with "iproc" processor
20393  GeneralisedElement* haloed_ele_pt =
20394  this->root_haloed_element_pt(iproc, ihd);
20395 
20396  // The counter for the nonhalo elements
20397  unsigned nh_count4 = 0;
20398  // Find the element in the general elements container
20399  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20400  {
20401  // Get the e-th element
20402  GeneralisedElement* ele_pt = this->element_pt(e);
20403  // Check if the element is a nonhalo element
20404  if (!ele_pt->is_halo())
20405  {
20406  // Increase the counter for nonhalo elements, in case the
20407  // haloed element is found get the (nh_count4-1) position
20408  // in the target domains vector
20409  nh_count4++;
20410 
20411  if (ele_pt == haloed_ele_pt)
20412  {
20413  // Get the new domain for this element
20414  const unsigned element_domain =
20415  target_domain_for_local_non_halo_element[nh_count4-1];
20416  // Here decrease the counter ---------------------^
20417 
20418  // Set the new domain for the haloed element in the
20419  // special container
20420  new_domains_haloed_elements[iproc][ihd] = element_domain;
20421 #ifdef PARANOID
20422  // Increase the counter
20423  counter_for_found_haloed_elements[iproc]++;
20424 #endif
20425  // ... and break the "for" with the general
20426  // elements. Continue with the next haloed element
20427  break;
20428 
20429  } // if (ele_pt == haloed_ele_pt))
20430 
20431  } // if (!ele_pt->is_halo())
20432 
20433  } // for (e < nelement_before_load_balance)
20434 
20435  } // for (ihd < n_haloed_iproc)
20436 
20437  } // if (iproc != my_rank)
20438 
20439  } // for (iproc < nproc)
20440 
20441 #ifdef PARANOID
20442  // Check that all the haloed elements with all processors have been
20443  // found
20444  for (unsigned iproc = 0; iproc < nproc; iproc++)
20445  {
20446  // There are no halo/haloed elements with myself (my_rank
20447  // processor)
20448  if (iproc != my_rank)
20449  {
20450  // Get the number of haloed elements with "iproc" processor
20451  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20452 
20453  // Compare the number of found haloed elements with the current
20454  // number of haloed elements
20455  if (n_haloed_iproc != counter_for_found_haloed_elements[iproc])
20456  {
20457  std::ostringstream error_message;
20458  error_message
20459  << "The independent counting of found haloed elements ("
20460  << counter_for_found_haloed_elements[iproc] << ") with processor ("
20461  << iproc << ") is not equal to the number of haloed elements ("
20462  << n_haloed_iproc << ") with processor (" << iproc << ")\n";
20463  throw OomphLibError(error_message.str(),
20464  OOMPH_CURRENT_FUNCTION,
20465  OOMPH_EXCEPTION_LOCATION);
20466  } // if (nhaloed_iproc == counter_for_found_haloed_elements[iproc])
20467 
20468  } // if (iproc != my_rank)
20469 
20470  } // for (iproc < nproc)
20471 #endif
20472 
20473  // Now we have the new domains for the haloed elements
20474 
20475  // Send this info. to the processor with a halo copy of the haloed
20476  // elements and set the new domains in the halo copies
20477 
20478  // First put all the info. in a flat package array
20479  Vector<unsigned> new_domains_haloed_flat_unsigned;
20480  // Put in a vector the number of haloed elements within each
20481  // processor
20482  Vector<int> nhaloed_elements_with_iproc(nproc);
20483  for (unsigned iproc = 0; iproc < nproc; iproc++)
20484  {
20485  // There are no halo/haloed elements with myself (my_rank
20486  // processor)
20487  if (iproc != my_rank)
20488  {
20489  // Get the number of haloed elements with "iproc" processor
20490  const unsigned n_haloed_ele_iproc = this->nroot_haloed_element(iproc);
20491  // Copy the number of haloed elements with "iproc" processor
20492  nhaloed_elements_with_iproc[iproc] = n_haloed_ele_iproc;
20493  // Copy the new domains of the haloed elements in the flat
20494  // package
20495  for (unsigned i = 0; i < n_haloed_ele_iproc; i++)
20496  {
20497  new_domains_haloed_flat_unsigned.push_back(
20498  new_domains_haloed_elements[iproc][i]);
20499  } // for (i < n_haloed_ele_iproc)
20500 
20501  } // if (iproc != my_rank)
20502 
20503  } // for (iproc < nproc)
20504 
20505  // The offsets of the flat package within each processor
20506  Vector<int> offset_haloed_elements_with_iproc(nproc);
20507  offset_haloed_elements_with_iproc[0] = 0;
20508  for (unsigned ip = 1; ip < nproc; ip++)
20509  {
20510  // Compute the offset to send the values to each processor
20511  offset_haloed_elements_with_iproc[ip] =
20512  offset_haloed_elements_with_iproc[ip-1] +
20513  nhaloed_elements_with_iproc[ip-1];
20514  } // for (ip < nproc)
20515 
20516  // Prepare to receive the data
20517 
20518  // Compute the number of data (halo elements) to receive from each
20519  // processor and the displacements within each processor
20520 
20521  // Counter for the total number of halo elements within all processors
20522  unsigned counter_halo_ele_with_all_procs = 0;
20523 
20524  // Put in a vector the number of halo elements expected to receive
20525  // from each processor
20526  Vector<int> nhalo_elements_with_iproc(nproc);
20527  // Compute the number of total halo elements of (my_rank) this
20528  // processor with all other processors
20529  for (unsigned iproc = 0; iproc < nproc; iproc++)
20530  {
20531  // There are no halo/haloed elements with myself (my_rank
20532  // processor)
20533  if (iproc != my_rank)
20534  {
20535  // Get the number of halo elements with "iproc" processor
20536  const unsigned n_halo_ele_iproc = this->nroot_halo_element(iproc);
20537  // Copy the number of halo elements with "iproc" processor
20538  nhalo_elements_with_iproc[iproc] = n_halo_ele_iproc;
20539  // Add the number of elements with this processor
20540  counter_halo_ele_with_all_procs+= n_halo_ele_iproc;
20541  } // if (iproc != my_rank)
20542 
20543  } // for (iproc < nproc)
20544 
20545  // The offsets of the flat package within each processor
20546  Vector<int> offset_halo_elements_with_iproc(nproc);
20547  offset_halo_elements_with_iproc[0] = 0;
20548  for (unsigned ip = 1; ip < nproc; ip++)
20549  {
20550  // Compute the offset to receive the values from each processor
20551  offset_halo_elements_with_iproc[ip] =
20552  offset_halo_elements_with_iproc[ip-1] +
20553  nhalo_elements_with_iproc[ip-1];
20554  } // for (ip < nproc)
20555 
20556  // The flat container to receive the new domains of the halo
20557  // elements in the current processor
20558 
20559  // The flat package where all the info. will be gather from the
20560  // other processors (the halo flat package)
20562  new_domains_halo_flat_unsigned(counter_halo_ele_with_all_procs);
20563 
20564  // Perform the sending and receiving of information to and from all
20565  // processors
20566  MPI_Alltoallv(&new_domains_haloed_flat_unsigned[0], // void *sendbuf
20567  &nhaloed_elements_with_iproc[0], // int *sendcnts
20568  &offset_haloed_elements_with_iproc[0], // int *sdispls
20569  MPI_UNSIGNED, // MPI_Datatype sendtype
20570  &new_domains_halo_flat_unsigned[0], // void *recvbuf
20571  &nhalo_elements_with_iproc[0], // int *recvcnts
20572  &offset_halo_elements_with_iproc[0], // int *rdispls
20573  MPI_UNSIGNED, // MPI_Datatype recvtype
20574  this->communicator_pt()->mpi_comm()); // MPI_Comm comm
20575 
20576  // Once received the new domains for the halo elements, copy the
20577  // domains back to an easier to handle container (from the flat
20578  // package to the one with the different halo elements domains
20579  // within each processor)
20580  unsigned counter_new_domains_halo_ele = 0;
20581  for (unsigned iproc = 0; iproc < nproc; iproc++)
20582  {
20583  // There are no halo/haloed elements with myself (my_rank
20584  // processor)
20585  if (iproc != my_rank)
20586  {
20587  // Get the number of halo elements with "iproc"
20588  const unsigned ntmp_halo_elements_with_iproc =
20589  nhalo_elements_with_iproc[iproc];
20590  // Loop over the number of halo elements within "iproc" and copy
20591  // the elements from the flat package
20592  for (unsigned i = 0; i < ntmp_halo_elements_with_iproc; i++)
20593  {
20594  // Copy the new domain of the halo elements from the flat
20595  // package to an easier to use container
20596  new_domains_halo_elements[iproc][i] =
20597  new_domains_halo_flat_unsigned[counter_new_domains_halo_ele++];
20598  }
20599  } // if (iproc != my_rank)
20600  } // for (iproc < nproc)
20601 
20602  // The time to get domains of halo elements
20603  if (Print_timings_level_load_balance>1)
20604  {
20605  oomph_info << "CPU for getting domains halo elements (load balance) [1]: "
20606  <<TimingHelpers::timer()-tt_start_get_domains_halo_elements
20607  << std::endl;
20608  }
20609 
20610  // =====================================================================
20611  // END: GET THE DOMAINS FOR THE HALO ELEMENTS
20612  // =====================================================================
20613 
20614  // =====================================================================
20615  // BEGIN: CREATE FINITE ELEMENT LOCAL VERSIONS OF THE HALO(ED)
20616  // ELEMENTS
20617  // =====================================================================
20618 
20619  // Get the time to get FiniteElement versions from Generalised
20620  // halo(ed) elements
20621  double tt_start_get_fe_version_from_ge_halo_ed=0.0;
20622  if (Print_timings_level_load_balance>1)
20623  {
20624  tt_start_get_fe_version_from_ge_halo_ed=TimingHelpers::timer();
20625  }
20626 
20627  // The finite element storage for the halo elements
20628  Vector<Vector<FiniteElement*> > f_halo_element_pt(nproc);
20629  // The finite element storage for the haloed elements
20630  Vector<Vector<FiniteElement*> > f_haloed_element_pt(nproc);
20631  // Loop over the processors
20632  for (unsigned iproc = 0; iproc < nproc; iproc++)
20633  {
20634  // There are no halo(ed) elements with myself
20635  if (iproc != my_rank)
20636  {
20637  // Get the number of halo elements with the "iproc" processor
20638  const unsigned nhalo_ele_iproc = this->nroot_halo_element(iproc);
20639  // Get the halo elements with the "iproc" processor
20640  Vector<GeneralisedElement*> halo_element_pt_iproc =
20641  this->root_halo_element_pt(iproc);
20642  // Resize the finite element container
20643  f_halo_element_pt[iproc].resize(nhalo_ele_iproc);
20644  // Loop over the halo elements
20645  for (unsigned ih = 0; ih < nhalo_ele_iproc; ih++)
20646  {
20647  // Get the finite element
20648  FiniteElement* ele_pt =
20649  dynamic_cast<FiniteElement*>(halo_element_pt_iproc[ih]);
20650  // Store the finite element version of the element
20651  f_halo_element_pt[iproc][ih] = ele_pt;
20652  } // for (ih < nhalo_ele_iproc)
20653 
20654  // Get the number of haloed elements with the "iproc" processor
20655  const unsigned nhaloed_ele_iproc = this->nroot_haloed_element(iproc);
20656  // Get the haloed elements with the "iproc" processor
20657  Vector<GeneralisedElement*> haloed_element_pt_iproc =
20658  this->root_haloed_element_pt(iproc);
20659  // Resize the finite element container
20660  f_haloed_element_pt[iproc].resize(nhaloed_ele_iproc);
20661  // Loop over the haloed elements
20662  for (unsigned ihd = 0; ihd < nhaloed_ele_iproc; ihd++)
20663  {
20664  // Get the finite element
20665  FiniteElement* ele_pt =
20666  dynamic_cast<FiniteElement*>(haloed_element_pt_iproc[ihd]);
20667  // Store the finite element version of the element
20668  f_haloed_element_pt[iproc][ihd] = ele_pt;
20669  } // for (ih < nhaloed_ele_iproc)
20670 
20671  } // if (iproc != my_rank)
20672 
20673  } // for (iproc < nproc)
20674 
20675  // The time to get FiniteElement versions from Generalised halo(ed)
20676  // elements
20677  if (Print_timings_level_load_balance>1)
20678  {
20679  oomph_info << "CPU for getting finite element versions from generalised halo(ed) elements (load balance) [2]: "
20680  <<TimingHelpers::timer()-tt_start_get_fe_version_from_ge_halo_ed
20681  << std::endl;
20682  }
20683 
20684  // =====================================================================
20685  // END: CREATE FINITE ELEMENT LOCAL VERSIONS OF THE HALO(ED)
20686  // ELEMENTS
20687  // =====================================================================
20688 
20689  // =====================================================================
20690  // BEGIN: 1) PREPARE THE ELEMENTS THAT WILL BE SENT TO OTHER PROCESSORS
20691  // ---- HALO ELEMENTS ARE NOT CONSIDERED FOR SENDING
20692  // 2) ASSOCIATE THE NODES WITH THE NEW DOMAIN OF THE ELEMENTS
20693  // ---- THE SAME IS PERFORMED FOR NODES IN HALO ELEMENTS
20694  // =====================================================================
20695 
20696  // Get the time to prepare elements to send to other processors
20697  double tt_start_prepare_element_to_send=0.0;
20698  if (Print_timings_level_load_balance>1)
20699  {
20700  tt_start_prepare_element_to_send=TimingHelpers::timer();
20701  }
20702 
20703  // Store the elements that will be sent to other processors
20704  Vector<Vector<FiniteElement*> > elements_to_send_pt(nproc);
20705 
20706  // Associate the nodes of each element with the processor the
20707  // element will live on
20708  std::map<Data*,std::set<unsigned> >
20709  processors_associated_with_data_before_load_balance;
20710 
20711  // Compute the elements that will be sent to other processor and
20712  // associate the nodes with the processor the element will live on
20713  unsigned nh_count3 = 0;
20714  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20715  {
20716  // Get the element
20717  FiniteElement *ele_pt = this->finite_element_pt(e);
20718  // Only work with nonhalo elements
20719  if (!(ele_pt->is_halo()))
20720  {
20721  // Get the new domain for the elment
20722  const unsigned element_domain =
20723  target_domain_for_local_non_halo_element[nh_count3++];
20724 
20725  // Include the element in the corresponding vector
20726  elements_to_send_pt[element_domain].push_back(ele_pt);
20727 
20728  // Get the number of nodes on the element
20729  const unsigned n_nodes = ele_pt->nnode();
20730  // Loop over the nodes
20731  for (unsigned j = 0; j < n_nodes; j++)
20732  {
20733  // Get each node of the element
20734  Node* node_pt = ele_pt->node_pt(j);
20735  // ... and associate it with element domains
20736  processors_associated_with_data_before_load_balance[node_pt].
20737  insert(element_domain);
20738 
20739  } // for (j < n_nodes)
20740 
20741  } // if (!(ele_pt->is_halo()))
20742 
20743  } // for (e < nelement_before_load_balance)
20744 
20745  // ... do the same for the halo elements (but do not add them to the
20746  // sending container since only the processor with the haloed
20747  // counterparts is in charge of that). Associate the nodes of the
20748  // halo elements with the processor they will live on
20749  for (unsigned iproc = 0; iproc < nproc; iproc++)
20750  {
20751  // There is no halo elements with myself
20752  if (iproc != my_rank)
20753  {
20754  // Get the number of halo elements with the "iproc" processor
20755  const unsigned n_halo_ele_iproc = this->nroot_halo_element(iproc);
20756  // Get the halo elements with the "iproc" processor
20757  Vector<GeneralisedElement*> halo_element_pt_iproc =
20758  this->root_halo_element_pt(iproc);
20759  // Loop over the halo elements with iproc
20760  for (unsigned ih = 0; ih < n_halo_ele_iproc; ih++)
20761  {
20762  // Get the new domain for the halo element
20763  const unsigned element_domain =
20764  new_domains_halo_elements[iproc][ih];
20765 
20766  // Get the finite element
20767  FiniteElement* ele_pt =
20768  dynamic_cast<FiniteElement*>(halo_element_pt_iproc[ih]);
20769 
20770  // Get the number of nodes on the halo element
20771  const unsigned n_nodes = ele_pt->nnode();
20772  // Loop over the nodes
20773  for (unsigned j = 0; j < n_nodes; j++)
20774  {
20775  // Get each node of the halo element
20776  Node* node_pt = ele_pt->node_pt(j);
20777 
20778  // ... and associate it with element domains
20779  processors_associated_with_data_before_load_balance[node_pt].
20780  insert(element_domain);
20781 
20782  } // for (j < n_nodes)
20783 
20784  } // for (ih < nhalo_ele_iproc)
20785 
20786  } // if (iproc != my_rank)
20787 
20788  } // for (iproc < nproc)
20789 
20790  // The time to prepare elements to send to other processors
20791  if (Print_timings_level_load_balance>1)
20792  {
20793  oomph_info << "CPU for preparing elements to send to other processors (load balance) [3]: "
20794  <<TimingHelpers::timer()-tt_start_prepare_element_to_send
20795  << std::endl;
20796  }
20797 
20798  // Now all the nodes are associated with the processor where the
20799  // element will live on. This is performed for the nonhalo and halo
20800  // elements
20801 
20802  // =====================================================================
20803  // END: 1) PREPARE THE ELEMENTS THAT WILL BE SENT TO OTHER PROCESSORS
20804  // ---- HALO ELEMENTS ARE NOT CONSIDERED FOR SENDING
20805  // 2) ASSOCIATE THE NODES WITH THE NEW DOMAIN OF THE ELEMENTS
20806  // ---- THE SAME IS PERFORMED FOR NODES IN HALO ELEMENTS
20807  // =====================================================================
20808 
20809  // =====================================================================
20810  // BEGIN: COMPUTE THE NEW LOCAL HALO ELEMENTS OF ALL PROCESSORS IN THE
20811  // CURRENT PROCESSOR
20812  // ----- FOR NONHALO ELEMENTS AND FOR HALO ELEMENTS
20813  // =====================================================================
20814 
20815  // Get the time to compute new local halo elements within all
20816  // processors
20817  double tt_start_compute_new_local_halo_elements=0.0;
20818  if (Print_timings_level_load_balance>1)
20819  {
20820  tt_start_compute_new_local_halo_elements=TimingHelpers::timer();
20821  }
20822 
20823  // Before sending the elements across compute the new local
20824  // halo/haloed elements of each processor. Each processor could have
20825  // elements that will be part of the new halo/haloed elements of
20826  // another processors, then these processors need to compute the
20827  // relations that may happen among these other processors
20828 
20829  // Example:
20830  // Processor 1 may have elements that will be sent to processor 3
20831  // and 4. These processors need to know about the new halo elements
20832  // betweeen them but at this moment only processor 1 can compute that
20833  // info., since it is the only one that currently has that info.
20834 
20835  // Store the new local-halo elements of each processor, the HALOED
20836  // elements are also stored in the container, only needs to INVERT
20837  // the indexes. For example, the HALO elements of processor 2 with
20838  // processor 3 are stored in new_local_halo_element_pt[2][3], and
20839  // the HALOED elements of processor 2 with processor 3 are stored in
20840  // new_local_halo_element_pt[3][2]. Notice that these are also the
20841  // halo elements of processor 3 with 2
20842 
20843  // How to identify the new local halo/haloed element: 1) Loop over
20844  // the element; 2) Only work with nonhalo elements; 3) If the
20845  // element is not assigned to the current processor (iproc) then
20846  // check; 4) Is one of its nodes assiociated to the iproc processor?
20847  // 5) If yes the element is a halo in the iproc processor whose
20848  // nonhalo counter part (haloed) lives in the domain assigned to the
20849  // element
20850  Vector<Vector<Vector<FiniteElement*> > > new_local_halo_element_pt(nproc);
20851 
20852  // Loop over the processors
20853  for (unsigned iproc = 0; iproc < nproc; iproc++)
20854  {
20855  // Resize the container
20856  new_local_halo_element_pt[iproc].resize(nproc);
20857 
20858  // Boolean to know which elements have been already added to the
20859  // new local halo scheme in "iproc"
20860  Vector<std::map<FiniteElement*,bool> > new_local_halo_already_added(nproc);
20861 
20862  // Go through all the elements and identify the new local halo
20863  // elements of "iproc"
20864  unsigned nh_count5 = 0;
20865  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20866  {
20867  // Get the element
20868  FiniteElement *ele_pt = this->finite_element_pt(e);
20869  // Only work with nonhalo elements
20870  if (!(ele_pt->is_halo()))
20871  {
20872  // Get the domain to which the current element is associated
20873  const unsigned ele_domain =
20874  target_domain_for_local_non_halo_element[nh_count5++];
20875  // If the current element is not associated to the "iproc"
20876  // processor then it could be a halo element
20877  if (ele_domain != iproc)
20878  {
20879  // Get the number of nodes
20880  const unsigned nnodes = ele_pt->nnode();
20881  // Loop over the nodes
20882  for (unsigned j = 0; j < nnodes; j++)
20883  {
20884  Node* node_pt = ele_pt->node_pt(j);
20885  // Check if the node is associated with the current
20886  // "iproc" processor
20887  std::set<unsigned>::iterator it =
20888  processors_associated_with_data_before_load_balance[node_pt].
20889  find(iproc);
20890  // If it is found then the element is a halo-element
20891  if (it!=
20892  processors_associated_with_data_before_load_balance[node_pt].
20893  end())
20894  {
20895  // Add the element as new local-halo element with the
20896  // "ele_domain" processor. The non-halo counterpart will
20897  // be located on "ele_domain" processor after sending
20898  // elements across
20899  if (!new_local_halo_already_added[ele_domain][ele_pt])
20900  {
20901  // The element is a halo element on "iproc" with
20902  // "ele_domain"
20903  new_local_halo_element_pt[iproc][ele_domain].
20904  push_back(ele_pt);
20905  // Mark as done
20906  new_local_halo_already_added[ele_domain][ele_pt] = true;
20907  } // if (!new_local_halo_already_added[ele_domain][ele_pt])
20908  } // One of the nodes lies on an element on the current
20909  // "iproc" processor
20910  } // for (j < nnodes)
20911  } // if (ele_domain != iproc)
20912  } // if (!(ele_pt->is_halo()))
20913  } // for (e < nelement_before_load_balance)
20914 
20915  // Now do the same with the halo elements, we need to find those
20916  // halo elements that continue being halo elements but possibly
20917  // with/on another processor. The pair of processors where a
20918  // possible shared boundary is created needs to be notified.
20919 
20920  // Example
20921  //
20922  // ---------------* *---------------
20923  // | |* *| |
20924  // | |* *| |
20925  // | New domain |* *| New domain | * Mark the position
20926  // | proc 1 |* *| proc 3 | of halo elements
20927  // | |* *| |
20928  // | |* *| |
20929  // ---------------* *---------------
20930  // Proc 1 Proc 2
20931 
20932  // Processor 1: The halo elements on processor 1 continue being halo ON
20933  // PROCESSOR 1, but now WITH PROCESSOR 3
20934 
20935  // Processor 2: The halo elements on processor 2 continue being
20936  // halo BUT now ON PROCESSOR 3 WITH PROCESSOR 1
20937 
20938  // The current processor (my_rank) also needs to consider the halo
20939  // elements that will be halo elements of other processor with
20940  // another processor. The case of processor 2
20941 
20942  // Loop over all the halo elements in the current processor and
20943  // check if they will be halo with the "iproc" processor
20944  for (unsigned jproc = 0; jproc < nproc; jproc++)
20945  {
20946  // There are no halo elements with myself (the old halo elements
20947  // were halo in the "my_rank" processor)
20948  if (jproc != my_rank)
20949  {
20950  // Get the number of halo elements with the "jproc" processor
20951  const unsigned n_halo_ele_jproc = this->nroot_halo_element(jproc);
20952  // Get the halo elements with the "jproc" processor
20953  Vector<GeneralisedElement*> halo_element_pt_jproc =
20954  this->root_halo_element_pt(jproc);
20955  // ... and check if any of those elements is a new halo
20956  // element with the "iproc" processor
20957  for (unsigned jh = 0; jh < n_halo_ele_jproc; jh++)
20958  {
20959  // Get the new domain for the halo element
20960  const unsigned ele_domain = new_domains_halo_elements[jproc][jh];
20961 
20962  // If the current element is not associated to the "iproc"
20963  // processor then it could be a halo element on "iproc" with
20964  // "ele_domain".
20965 
20966  // NOTE OUTDATE: Check if the halo element is going to be
20967  // sent to this processor (my_rank), if that is the case
20968  // then we don't need to add it to the set of new halo
20969  // elements with any other processor since any possible
20970  // shared boundary will be created when checking for the
20971  // intersection of the sent and received elements
20972 
20973  //if (ele_domain != iproc && ele_domain != my_rank)
20974 
20975  // NOTE UPDATE: Only check if the halo element is not going
20976  // to be part of the iproc processor, not required to avoid
20977  // those halo elements whose domain is the current rank
20978  // (my_rank). When the shared boundaries are computed, these
20979  // last elements can not create a shared boundary since no
20980  // haloed elements (that shared an edge) are found for
20981  // them. By considering also those halo elements whose new
20982  // domain is the current one (commenting "ele_domain !=
20983  // my_rank") the current processor can compute shared
20984  // boundaries with the iproc processor with help of its old
20985  // halo elements but that will become nonhalo elements, in
20986  // fact they will become haloed elements The halo element is
20987  // not sent to the "element_domain" processor and is not
20988  // passed to the array used to create the new shared
20989  // boundaries "new_shared_boundary_element_pt" because of
20990  // its halo condition
20991  if (ele_domain != iproc)
20992  {
20993  // Get the finite element
20994  FiniteElement* ele_pt =
20995  dynamic_cast<FiniteElement*>(halo_element_pt_jproc[jh]);
20996  // Get the number of nodes on the halo element
20997  const unsigned nnodes = ele_pt->nnode();
20998  // Loop over the nodes
20999  for (unsigned j = 0; j < nnodes; j++)
21000  {
21001  // Get each node of the halo element
21002  Node* node_pt = ele_pt->node_pt(j);
21003 
21004  // Check if the node is associated with the "iproc"
21005  // processor
21006  std::set<unsigned>::iterator it =
21007  processors_associated_with_data_before_load_balance[node_pt].
21008  find(iproc);
21009  // If it is found then the element is a halo-element
21010  if (it!=
21011  processors_associated_with_data_before_load_balance[node_pt].end())
21012  {
21013  // Add the element as new local-halo element with
21014  // the "ele_domain" processor. The non-halo
21015  // counterpart will be located on "ele_domain"
21016  // processor. Because this is a old-halo element it
21017  // will not be sent to the "element_domain" processor
21018  if (!new_local_halo_already_added[ele_domain][ele_pt])
21019  {
21020  // The element is a halo element on "iproc" with
21021  // "ele_domain"
21022  new_local_halo_element_pt[iproc][ele_domain].
21023  push_back(ele_pt);
21024  new_local_halo_already_added[ele_domain][ele_pt] = true;
21025 
21026  // Break the for of the nodes, the element has been
21027  // already added to the new_local_halo_element_pt
21028  // structure
21029  break;
21030 
21031  } // if (!new_local_halo_already_added[ele_domain][ele_pt])
21032 
21033  } // One of the nodes lies on an element belonging to
21034  // "iproc" processor
21035 
21036  } // for (j < nnodes)
21037 
21038  } // if (ele_domain != iproc)
21039 
21040  } // for (jh < n_halo_ele_jproc)
21041 
21042  } // if (jproc != my_rank) // The old halo elements are halo
21043  // with other processors except with "my_rank"
21044 
21045  } // for (jproc < nproc): This is the one that goes for the halo
21046  // elements in the current processor to find the new halo
21047  // elements
21048 
21049  } // for (iproc < nproc)
21050 
21051  // Get the time to compute new local halo elements within all
21052  // processors
21053  if (Print_timings_level_load_balance>1)
21054  {
21055  oomph_info << "CPU for computing new local halo elements (load balance) [4]: "
21056  <<TimingHelpers::timer()-tt_start_compute_new_local_halo_elements
21057  << std::endl;
21058  }
21059 
21060  // =====================================================================
21061  // END: COMPUTE THE NEW LOCAL HALO ELEMENTS OF ALL PROCESSORS IN THE
21062  // CURRENT PROCESSOR
21063  // ----- FOR NONHALO ELEMENTS AND FOR HALO ELEMENTS
21064  // =====================================================================
21065 
21066  // =====================================================================
21067  // BEGIN: COMPUTE THE NEW LOCAL SHARED BOUNDARY ELEMENTS AND THE
21068  // FACE ELEMENTS. THE SUBSET OF THE ELEMENTS TO SENT THAT ARE PART
21069  // OF THE NEW LOCAL SHARED BOUNDARY ELEMENTS ARE IDENTIFIED TO BE
21070  // MARKED AS HALOED ELEMENTS AND BELONGING TO THE SHARED BOUNDARY
21071  // ELEMENTS IN THE RECEIVED PROCESSOR
21072  // =====================================================================
21073 
21074  // Get the time to compute new local shared boundary elements
21075  double tt_start_compute_new_local_shd_bnd_ele=0.0;
21076  if (Print_timings_level_load_balance>1)
21077  {
21078  tt_start_compute_new_local_shd_bnd_ele=TimingHelpers::timer();
21079  }
21080 
21081  // Store the new local-shared boundary elements and the face indexes
21082  // The halo elements and halo face indexes
21084  new_local_halo_shared_boundary_element_pt(nproc);
21086  new_local_halo_shared_boundary_element_face_index(nproc);
21087 
21088  // Allocate enough memory for the containers
21089  for (unsigned iproc = 0; iproc < nproc; iproc++)
21090  {
21091  new_local_halo_shared_boundary_element_pt[iproc].resize(nproc);
21092  new_local_halo_shared_boundary_element_face_index[iproc].resize(nproc);
21093  } // for (iproc < nproc)
21094 
21095  // Get the elements that create the new local-halo-shared
21096  // boundaries, mark them and identify the face that lies on the
21097  // shared boundary. The new local-halo-shared boundary elements are
21098  // actually a sub-set of the halo elements of each processor with in
21099  // each processor
21100  for (unsigned iproc = 0; iproc < nproc; iproc++)
21101  {
21102  // Star from jproc = iproc + 1 to avoid double creation of shared
21103  // boundary elements, any shared boundary element identified
21104  // between processor "iproc" and "jproc" is also established as
21105  // shared boundary element between processor "jproc" and "iproc"
21106  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
21107  {
21108  this->get_shared_boundary_elements_and_face_indexes(
21109  new_local_halo_element_pt[iproc][jproc],
21110  new_local_halo_element_pt[jproc][iproc],
21111  new_local_halo_shared_boundary_element_pt[iproc][jproc],
21112  new_local_halo_shared_boundary_element_face_index[iproc][jproc],
21113  new_local_halo_shared_boundary_element_pt[jproc][iproc],
21114  new_local_halo_shared_boundary_element_face_index[jproc][iproc]);
21115  } // for (jproc < nproc)
21116  } // for (iproc < nproc)
21117 
21118  // The time to compute new local shared boundary elements
21119  if (Print_timings_level_load_balance>1)
21120  {
21121  oomph_info << "CPU for computing new local shared boundary elements (load balance) [5]: "
21122  <<TimingHelpers::timer()-tt_start_compute_new_local_shd_bnd_ele
21123  << std::endl;
21124  }
21125 
21126  // =====================================================================
21127  // END: COMPUTE THE NEW LOCAL SHARED BOUNDARY ELEMENTS AND THE FACE
21128  // ELEMENTS. THE SUBSET OF THE ELEMENTS TO SENT THAT ARE PART OF THE
21129  // NEW LOCAL SHARED BOUNDARY ELEMENTS ARE IDENTIFIED TO BE MARKED AS
21130  // HALOED ELEMENTS AND BELONGING TO THE SHARED BOUNDARY ELEMENTS IN
21131  // THE RECEIVED PROCESSOR
21132  // =====================================================================
21133 
21134  // =====================================================================
21135  // BEGIN: SEND THE ELEMENTS AND IDENTIFY THOSE THAT ARE PART OF THE
21136  // SHARED BOUNDARIES AND HALOED WITH OTHER PROCESSORS
21137  // =====================================================================
21138 
21139  // Get the time to send the elements to their new processor in
21140  // charge
21141  double tt_start_send_elements_to_other_processors=0.0;
21142  if (Print_timings_level_load_balance>1)
21143  {
21144  tt_start_send_elements_to_other_processors=TimingHelpers::timer();
21145  }
21146 
21147  // Sort the nodes on shared boundaries so that they have the same
21148  // order on all the shared boundaries, this is required to know the
21149  // possible shared nodes among processors
21150  this->sort_nodes_on_shared_boundaries();
21151 
21152  // Store the received elements from each processor
21153  Vector<Vector<FiniteElement*> > received_elements_pt(nproc);
21154 
21155  // The haloed elements and haloed face indexes, these store the
21156  // haloed elements received from "iproc" but that are haloed with
21157  // "jproc". The elements are received from "iproc" which was the
21158  // processor that computed the haloed relation of the "my_rank"
21159  // processor with "jproc"
21161  new_received_haloed_shared_boundary_element_pt(nproc);
21163  new_received_haloed_shared_boundary_element_face_index(nproc);
21164 
21165  // Container where to store the nodes on shared boundaries not
21166  // associated with the processor that receives the elements/nodes
21167  // other_proc_shd_bnd_node_pt[iproc][jproc][shd_bnd_id][index]
21169  other_proc_shd_bnd_node_pt(nproc);
21170  // Resize the container
21171  for (unsigned iproc = 0; iproc < nproc; iproc++)
21172  {
21173  // Resize the container
21174  other_proc_shd_bnd_node_pt[iproc].resize(nproc);
21175  for (unsigned jproc = 0; jproc < nproc; jproc++)
21176  {
21177  // Get the number of shared boundaries (OLD shared boundaries)
21178  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
21179  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
21180  const unsigned n_shared_bound = final_shd_bnd_id - initial_shd_bnd_id;
21181  other_proc_shd_bnd_node_pt[iproc][jproc].resize(n_shared_bound);
21182  } // for (jproc < nproc)
21183 
21184  } // for (iproc < nproc)
21185 
21186  // Store the global node names
21187  // global_node_name[x][ ][ ] Global node number
21188  // global_node_name[ ][x][ ] Global node names
21189  // global_node_name[ ][ ][x] Global node info.
21190  Vector<Vector<Vector<unsigned> > > global_node_names;
21191 
21192  // Creates a map between the node name and the index of the global
21193  // node so we can access all its node names
21194  std::map<Vector<unsigned>, unsigned> node_name_to_global_index;
21195 
21196  // Store the global shared nodes pointers
21197  Vector<Node*> global_shared_node_pt;
21198 
21199  // Compute all the names of the nodes and fill in the
21200  // "other_proc_shd_bnd_node_pt" structure with the nodes that live
21201  // on this processor (my_rank) by looking over all their names
21202  compute_global_node_names_and_shared_nodes(other_proc_shd_bnd_node_pt,
21203  global_node_names,
21204  node_name_to_global_index,
21205  global_shared_node_pt);
21206 
21207  // From the elements received from each processor, store the haloed
21208  // information of the element, it means, the processor with which it
21209  // is haloed and the haloed index with that processor
21211  received_old_haloed_element_pt(nproc);
21212  // [x][][] : The receiver processor (the original processor)
21213  // [][x][] : The processor with which the receiver processor has
21214  // haloed elements
21215  // [][][x]: The haloed element number
21216 
21217  // Resize the container
21218  for (unsigned iproc = 0; iproc < nproc; iproc++)
21219  {
21220  received_old_haloed_element_pt[iproc].resize(nproc);
21221  } // for (iproc < nproc)
21222 
21223  // Go through all processors and send the corresponding elements to
21224  // each one
21225  for (unsigned iproc = 0; iproc < nproc; iproc++)
21226  {
21227  if (iproc != my_rank)
21228  {
21229  // -----------------------------------------------------------
21230  // Send (package) information of the elements
21231  // -----------------------------------------------------------
21232 
21233  // Keep track of the currently sent elements
21234  Vector<FiniteElement*> currently_sent_elements;
21235  // Keep track of the currently sent nodes to the iproc processor
21236  Vector<Node*> currently_sent_nodes;
21237 
21238  // Clear send and receive buffers
21239  Flat_packed_unsigneds.clear();
21240  Flat_packed_doubles.clear();
21241 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21243 #endif
21244 
21245  // Get the number of elements to send to iproc processor
21246  const unsigned nelements_to_send = elements_to_send_pt[iproc].size();
21247 
21248  // The very first data of the flat package sent to processor
21249  // iproc is the number of elements that will be sent, this data
21250  // is used by the receiver processor to loop over the number of
21251  // expected elements to receive
21252  Flat_packed_unsigneds.push_back(nelements_to_send);
21253 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21254  std::stringstream junk;
21255  junk << "Number of elements to send from processor " << my_rank
21256  << " to processor " << iproc << ": ("
21257  << nelements_to_send << ")";
21258  Flat_packed_unsigneds_string.push_back(junk.str());
21259 #endif
21260 
21261  // Loop over the elements to sent
21262  for (unsigned e = 0; e < nelements_to_send; e++)
21263  {
21264  // Get the element to send
21265  FiniteElement* send_ele_pt = elements_to_send_pt[iproc][e];
21266 
21267  // Get the current number of sent elements
21268  const unsigned ncurrently_sent_elements =
21269  currently_sent_elements.size();
21270 
21271  // Try to add the element
21272  const unsigned index_ele = try_to_add_element_pt_load_balance(
21273  currently_sent_elements, send_ele_pt);
21274 
21275  // Element needs to be added
21276  if (index_ele == ncurrently_sent_elements)
21277  {
21278  Flat_packed_unsigneds.push_back(1);
21279 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21280  Flat_packed_unsigneds_string.push_back("Element needs to be constructed");
21281 #endif
21282 
21283  // Get required info. related with the element
21284  get_required_elemental_information_load_balance_helper(
21285  iproc,
21286  f_haloed_element_pt,
21287  send_ele_pt);
21288 
21289  // Get the number of nodes in the element
21290  const unsigned nnodes = send_ele_pt->nnode();
21291 
21292  // Loop over the nodes in the element
21293  for (unsigned j = 0; j < nnodes; j++)
21294  {
21295  Node* node_pt = send_ele_pt->node_pt(j);
21296 
21297  // Package the info. of the nodes
21298  add_node_load_balance_helper(iproc, // The destination process
21299  f_halo_element_pt,
21300  currently_sent_nodes,
21301  node_pt);
21302 
21303  } // for (j < nnodes)
21304 
21305  } // if (index_ele == ncurrently_sent_elements)
21306  else
21307  {
21308  Flat_packed_unsigneds.push_back(0);
21309 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21310  Flat_packed_unsigneds_string.push_back("Element already exists");
21311 #endif
21312  Flat_packed_unsigneds.push_back(index_ele);
21313 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21314  Flat_packed_unsigneds_string.push_back("Index of existing element");
21315 #endif
21316  } // else if (index_ele == ncurrently_sent_elements)
21317 
21318  } // for (e < nelements_to_send)
21319 
21320  // After storing the info. of the elements identify the indexes
21321  // of the "new_local_halo_shared_boundary_elements" in the
21322  // "currently_send_elements" vector, these elements will be
21323  // identified as "new_received_haloed_shared_boundary_elements"
21324  // on the "receiver" processor
21325 
21326  // Each processor has information of every other processor so we
21327  // need to send all the corresponding info. to the other
21328  // processors. Processor 1 may have information of the relation
21329  // (halo elements) between processor 3 and 4 say, so processor 1
21330  // needs to let know processor 3 and 4 what this relation is
21331  // (which are the shared-elements among these processors)
21332 
21333  for (unsigned jproc = 0; jproc < nproc; jproc++)
21334  {
21335  // Get the number of new local-halo shared boundary elements
21336  // between processor "jproc" and "iproc" (we invert the index
21337  // since we really want the haloed elements, those elements
21338  // that we have just sent)
21339  const unsigned njproc_iproc_new_local_halo_shared_boundary_ele =
21340  new_local_halo_shared_boundary_element_pt[jproc][iproc].size();
21341 
21342  // The vector with the info. of the indexes
21343  Vector<unsigned> new_local_halo_shared_boundary_ele_index;
21344 
21345  // The number of found shared boundary elements in the sent
21346  // container (only consider the nonhalo elements)
21347  unsigned nfound_new_local_halo_shared_bound_ele_index = 0;
21348  // The number of nonhalo elements in the new local halo shared
21349  // boundary elements
21350  unsigned nnon_halo_new_local_halo_shared_bound_ele = 0;
21351 
21352  // Loop over the local halo shared boundary elements between
21353  // processor jproc and iproc
21354  for (unsigned e = 0;
21355  e < njproc_iproc_new_local_halo_shared_boundary_ele; e++)
21356  {
21357  // Get the shared boundary element
21358  FiniteElement* shared_ele_pt =
21359  new_local_halo_shared_boundary_element_pt[jproc][iproc][e];
21360 
21361  // Only consider the nonhalo elements since the halo
21362  // elements were no considered for sending
21363  if (!shared_ele_pt->is_halo())
21364  {
21365  nnon_halo_new_local_halo_shared_bound_ele++;
21366 
21367  // Now find the index on the currently sent elements
21368 
21369  // Get the current number of sent elements
21370  const unsigned ncurrently_sent_elements =
21371  currently_sent_elements.size();
21372  // Loop over the sent elements
21373  for (unsigned ics = 0; ics < ncurrently_sent_elements; ics++)
21374  {
21375  FiniteElement* currently_sent_ele_pt =
21376  currently_sent_elements[ics];
21377 
21378  // Is this the element?
21379  if (currently_sent_ele_pt == shared_ele_pt)
21380  {
21381  // Store the index on the sent elements of the local
21382  // halo shared boundary element
21383  new_local_halo_shared_boundary_ele_index.push_back(ics);
21384  // Increase the number of found new local halo shared
21385  // bound element index
21386  nfound_new_local_halo_shared_bound_ele_index++;
21387  // We have found it, no need to further search
21388  break;
21389  } // if (currently_sent_ele_pt == shared_ele_pt)
21390 
21391  } // for (ics < ncurrently_sent_elements)
21392 
21393  } // if (!shared_ele_pt->is_halo())
21394 
21395  } // for (e < niproc_new_local_halo_shared_boundary_ele)
21396 
21397 #ifdef PARANOID
21398  if (nfound_new_local_halo_shared_bound_ele_index !=
21399  nnon_halo_new_local_halo_shared_bound_ele)
21400  {
21401  std::ostringstream error_message;
21402  error_message
21403  << "Was only possible to identify ("
21404  << nfound_new_local_halo_shared_bound_ele_index << ") of ("
21405  << nnon_halo_new_local_halo_shared_bound_ele << ") shared "
21406  << "elements between\nprocessor ("<<iproc<<") and ("<<jproc<<") "
21407  << "when sending elements to processor ("<<iproc<<")\n\n";
21408  throw OomphLibError(error_message.str(),
21409  OOMPH_CURRENT_FUNCTION,
21410  OOMPH_EXCEPTION_LOCATION);
21411  }
21412 #endif
21413 
21414  // Send a flag for synchronisation issues
21415  Flat_packed_unsigneds.push_back(9999);
21416 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21417  std::stringstream junk;
21418  junk << "Flag for synchronisation 9999";
21419  Flat_packed_unsigneds_string.push_back(junk.str());
21420 #endif
21421 
21422  // Send the number of nonhalo new local-shared boundary
21423  // elements of processor "iproc" with processor "jproc"
21424  Flat_packed_unsigneds.push_back(nnon_halo_new_local_halo_shared_bound_ele);
21425 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21426  std::stringstream junk2;
21427  junk2 << "Number of new local halo shared boundary elements "
21428  << nnon_halo_new_local_halo_shared_bound_ele;
21429  Flat_packed_unsigneds_string.push_back(junk2.str());
21430 #endif
21431 
21432  // Send the indexes and the face indexes of the shared
21433  // boundary elements
21434  unsigned counter_nonhalo_sent = 0;
21435  // Loop over the local halo shared boundary elements between
21436  // processor jproc and iproc
21437  for (unsigned e = 0;
21438  e < njproc_iproc_new_local_halo_shared_boundary_ele; e++)
21439  {
21440  // Get the shared boundary element
21441  FiniteElement* shared_ele_pt =
21442  new_local_halo_shared_boundary_element_pt[jproc][iproc][e];
21443 
21444  // Only consider the nonhalo elements since the halo
21445  // elements were no considered for sending
21446  if (!shared_ele_pt->is_halo())
21447  {
21448  // Get the index on the sent elements of the current
21449  // nonhalo shared boundary element
21450  const unsigned ele_index =
21451  new_local_halo_shared_boundary_ele_index[counter_nonhalo_sent++];
21452  // ... and get the face index
21453  const unsigned face_index =
21454  new_local_halo_shared_boundary_element_face_index[jproc][iproc][e];
21455 
21456  // Send the index on the sent elements of the new local
21457  // halo shared boundary element
21458  Flat_packed_unsigneds.push_back(ele_index);
21459 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21460  std::stringstream junk;
21461  junk << "The index of the halo shared boundary element "
21462  << ele_index;
21463  Flat_packed_unsigneds_string.push_back(junk.str());
21464 #endif
21465 
21466  // Send the face index of the new local halo shared boundary
21467  // element
21468  Flat_packed_unsigneds.push_back(face_index);
21469 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21470  std::stringstream junk2;
21471  junk2 << "The face index of the halo shared boundary element "
21472  << face_index;
21473  Flat_packed_unsigneds_string.push_back(junk2.str());
21474 #endif
21475 
21476  } // if (!shared_ele_pt->is_halo())
21477 
21478  } // for (e < niproc_new_local_halo_shared_boundary_ele)
21479 
21480  } // for (jproc < nproc)
21481 
21482  // ----------------------------------------------------------
21483  // Send the info. perform the communications
21484  // ----------------------------------------------------------
21485  // Processor to which send the info.
21486  int send_proc = static_cast<int>(iproc);
21487  // Processor from which receive the info.
21488  int recv_proc = static_cast<int>(iproc);
21489  send_and_receive_elements_nodes_info(send_proc, recv_proc);
21490 
21491  // ----------------------------------------------------------
21492  // Receive (unpackage) the info of the elements
21493  // ----------------------------------------------------------
21494 
21495  // Keep track of the currently created elements
21496  Vector<FiniteElement*> currently_created_elements;
21497  // Keep track of the currently created nodes
21498  Vector<Node*> currently_created_nodes;
21499 
21500  // Reset the counters
21503 
21504 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21506  << " Number of elements need to be constructed "
21508  << std::endl;
21509 #endif
21510 
21511  // Read the number of elements that need to be created
21512  const unsigned nelements_to_create =
21514 
21515  for (unsigned e = 0; e < nelements_to_create; e++)
21516  {
21517  // Create the element from received info. of "iproc"
21518  // processor on the current processor
21519  create_element_load_balance_helper(iproc,
21520  f_haloed_element_pt,
21521  received_old_haloed_element_pt,
21522  currently_created_elements,
21523  currently_created_nodes,
21524  other_proc_shd_bnd_node_pt,
21525  global_node_names,
21526  node_name_to_global_index,
21527  global_shared_node_pt);
21528  }
21529 
21530  // Copy the received elements from "iproc" processor
21531 
21532  // Number of received elements
21533  const unsigned nreceived_elements = currently_created_elements.size();
21534  received_elements_pt[iproc].resize(nreceived_elements);
21535  for (unsigned e = 0; e < nreceived_elements; e++)
21536  {received_elements_pt[iproc][e] = currently_created_elements[e];}
21537 
21538  // Go for the haloed elements received from processor "iproc"
21539  // but haloed with "jproc"
21540 
21541  // Allocate memory for the containers
21542  new_received_haloed_shared_boundary_element_pt[iproc].resize(nproc);
21543  new_received_haloed_shared_boundary_element_face_index[iproc].resize(nproc);
21544 
21545  // Loop over the processors
21546  for (unsigned jproc = 0; jproc < nproc; jproc++)
21547  {
21548  // Read the synchronisation flag
21549  const unsigned synchronisation_flag =
21551 
21552  if (synchronisation_flag != 9999)
21553  {
21554  std::ostringstream error_message;
21555  error_message
21556  << "The synchronisation flag was not read, the\n"
21557  << "information sent between processor (" << my_rank << ") "
21558  << "and ("<< iproc << ")\nis no longer synchronised\n\n";
21559  throw OomphLibError(error_message.str(),
21560  OOMPH_CURRENT_FUNCTION,
21561  OOMPH_EXCEPTION_LOCATION);
21562  }
21563 
21564  // Read the number of elements that will be part of the new
21565  // received haloed shared boundary elements received from "iproc"
21566  // and haloed with "jproc"
21567  const unsigned niproc_jproc_new_received_haloed_shared_boundary_ele =
21569 
21570  // Loop over the new received haloed shared boundary elements
21571  for (unsigned e = 0;
21572  e < niproc_jproc_new_received_haloed_shared_boundary_ele; e++)
21573  {
21574  // Read the index of the new received haloed shared boundary
21575  // ele with "jproc"
21576  const unsigned ele_index =
21578  // Read the face index for the new received haloed shared
21579  // boundary element
21580  const unsigned face_index =
21582 
21583  // Get the element
21584  FiniteElement* shared_ele_pt =
21585  currently_created_elements[ele_index];
21586 
21587  // Add the element to the new received-haloed shared
21588  // boundary elements. Received from "iproc" but haloed with
21589  // "jproc" processor
21590  new_received_haloed_shared_boundary_element_pt[iproc][jproc].
21591  push_back(shared_ele_pt);
21592  // Store the face index
21593  new_received_haloed_shared_boundary_element_face_index[iproc][jproc].
21594  push_back(face_index);
21595 
21596  } // for (e < niproc_jproc_read_new_local_shared_boundary_ele)
21597 
21598  } // for (jproc < nproc)
21599 
21600  } // if (iproc != my_rank)
21601 
21602  } // for (iproc < nproc)
21603 
21604  // The time to send the elements to their new processor in charge
21605  if (Print_timings_level_load_balance>1)
21606  {
21607  oomph_info << "CPU for sending elements to their new processors (load balance) [6]: "
21608  <<TimingHelpers::timer()-tt_start_send_elements_to_other_processors
21609  << std::endl;
21610  }
21611 
21612  // =====================================================================
21613  // END: SEND THE ELEMENTS AND IDENTIFY THOSE THAT ARE PART OF THE
21614  // SHARED BOUNDARIES AND HALOED WITH OTHER PROCESSORS
21615  // =====================================================================
21616 
21617  // =====================================================================
21618  // BEGIN: GET ANY ADDITIONAL SHARED BOUNDARY BY THE INTERSECTION OF
21619  // THE ELEMENTS SENT TO PROCESSOR "IPROC" AND THE ELEMENTS RECEIVED
21620  // FROM PROCESSOR "IPROC". IF ANY NEW SHARED BOUNDARY IS FOUND, IT
21621  // IS CREATED BY THE OLD HALO ELEMENTS (RECEIVED ELEMENTS) THAT HAVE
21622  // NOW BECOME PART OF THE DOMAIN AND THE OLD HALOED ELEMENTS (SENT
21623  // ELEMENTS)
21624  // =====================================================================
21625 
21626  // Get the time to compute any additional shared boundary
21627  double tt_start_compute_additional_shared_boundaries=0.0;
21628  if (Print_timings_level_load_balance>1)
21629  {
21630  tt_start_compute_additional_shared_boundaries=TimingHelpers::timer();
21631  }
21632 
21633  // Store any additional elements that may create a shared boundary,
21634  // after sending elements from one to other processor check for any
21635  // new possible shared boundaries
21637  tmp_group1_shared_boundary_element_pt(nproc);
21639  tmp_group1_shared_boundary_element_face_index(nproc);
21641  tmp_group2_shared_boundary_element_pt(nproc);
21643  tmp_group2_shared_boundary_element_face_index(nproc);
21644 
21645  // Compute any additional shared boundaries by checking the
21646  // intersection between the received elements from each processor
21647  // and the elements just sent to that processor, the lowest
21648  // processors number loops over its received elements and the
21649  // highest loops over its sent elements (halo elements that have
21650  // become part of the domain now can create shared boundaries with
21651  // other processor)
21652 
21653  // Note: These additional shared boundaries may be created by the
21654  // elements that previously were halo but now have become part of
21655  // the processor (the received elements), and the elements that were
21656  // previously part of the processor but now have become halo (a
21657  // subset of the sent-elements)
21658 
21659  // Then these new shared boundaries come from the intersection of
21660  // the new-haloed elements (received elements) and the new-halo
21661  // elements (sent elements). These could be computed previously (in
21662  // the computing of the local new-halo and local new-haloed elements
21663  // usign the info. of the new domains for the old halo elements),
21664  // however, it was decided to perform the computation here in order to
21665  // avoid the identification of the old halo element that was part of a
21666  // shared boundary in the set of just received elements
21667  for (unsigned iproc = 0; iproc < nproc; iproc++)
21668  {
21669  if (my_rank < iproc)
21670  {
21671  // Lowest processor loops over the received elements
21672  this->get_shared_boundary_elements_and_face_indexes(
21673  received_elements_pt[iproc], elements_to_send_pt[iproc],
21674  tmp_group1_shared_boundary_element_pt[iproc],
21675  tmp_group1_shared_boundary_element_face_index[iproc],
21676  tmp_group2_shared_boundary_element_pt[iproc],
21677  tmp_group2_shared_boundary_element_face_index[iproc]);
21678 
21679  } // if (my_rank < iproc)
21680  else if (my_rank > iproc)
21681  {
21682  // Highest processor loops over the sent elements
21683  this->get_shared_boundary_elements_and_face_indexes(
21684  elements_to_send_pt[iproc], received_elements_pt[iproc],
21685  tmp_group1_shared_boundary_element_pt[iproc],
21686  tmp_group1_shared_boundary_element_face_index[iproc],
21687  tmp_group2_shared_boundary_element_pt[iproc],
21688  tmp_group2_shared_boundary_element_face_index[iproc]);
21689 
21690  } // else if (my_rank > iproc)
21691 
21692  } // for (iproc < nproc)
21693 
21694  // The time to compute any additional shared boundary
21695  if (Print_timings_level_load_balance>1)
21696  {
21697  oomph_info << "CPU for computing additional shared boundaries (load balance) [7]: "
21698  <<TimingHelpers::timer()-tt_start_compute_additional_shared_boundaries
21699  << std::endl;
21700  }
21701 
21702  // =====================================================================
21703  // END: GET ANY ADDITIONAL SHARED BOUNDARY BY THE INTERSECTION OF
21704  // THE ELEMENTS SENT TO PROCESSOR "IPROC" AND THE ELEMENTS RECEIVED
21705  // FROM PROCESSOR "IPROC". IF ANY NEW SHARED BOUNDARY IS FOUND, IT
21706  // IS CREATED BY THE OLD HALO ELEMENTS (RECEIVED ELEMENTS) THAT HAVE
21707  // NOW BECOME PART OF THE DOMAIN AND THE OLD HALOED ELEMENTS (SENT
21708  // ELEMENTS)
21709  // =====================================================================
21710 
21711  // =====================================================================
21712  // BEGIN: SORT THE SHARED BOUNDARIES SO THAT THEY ARE CREATED IN THE
21713  // SAME ORDER IN THE INVOLVED PROCESSORS (A PAIR OF PROCESSORS)
21714  // =====================================================================
21715 
21716  // Get the time to sort shared boundaries
21717  double tt_start_sort_shared_boundaries=0.0;
21718  if (Print_timings_level_load_balance>1)
21719  {
21720  tt_start_sort_shared_boundaries=TimingHelpers::timer();
21721  }
21722 
21723  // Once computed the elements that create the shared boundaries,
21724  // sort them so that the shared boundaries are created at the same
21725  // order in both processors that define the shared boundary
21726 
21727  // The order is like this
21728 
21729  // Lowest processors
21730  // 1) Shared boundary elements received from processors (local in
21731  // other processors)
21732  // 2) Local shared boundary elements (do not include halo elements)
21733  // 3) Shared boundary elements by intersection (already sorted)
21734 
21735  // Highest processors
21736  // 1) Local shared boundary elements (do not include halo elements)
21737  // 2) Shared boundary elements received from processors (local in
21738  // other processors)
21739  // 3) Shared boundary elements by intersection (already sorted)
21740 
21741  Vector<Vector<FiniteElement*> > new_shared_boundary_element_pt(nproc);
21742  Vector<Vector<unsigned> > new_shared_boundary_element_face_index(nproc);
21743  for (unsigned iproc = 0; iproc < nproc; iproc++)
21744  {
21745  // Lower processor
21746  if (my_rank < iproc)
21747  {
21748  // Copy the elements received from processor "jproc" but that
21749  // are haloed with "iproc" processor
21750  for (unsigned jproc = 0; jproc < nproc; jproc++)
21751  {
21752  // Can not receive elements from itself
21753  if (jproc != my_rank)
21754  {
21755  // Get the number of elements to copy from received processors
21756  const unsigned nrecvd_haloed_shared_bound_ele_jproc_iproc =
21757  new_received_haloed_shared_boundary_element_pt[jproc][iproc].size();
21758  for (unsigned e = 0;
21759  e < nrecvd_haloed_shared_bound_ele_jproc_iproc; e++)
21760  {
21761  // Get the element
21762  FiniteElement* ele_pt =
21763  new_received_haloed_shared_boundary_element_pt[jproc][iproc][e];
21764  // Get the face index
21765  const unsigned face_index =
21766  new_received_haloed_shared_boundary_element_face_index[jproc][iproc][e];
21767 
21768  // Add the elements to the containers
21769  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21770  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21771 
21772  } // for (e < nrecvd_haloed_shared_bound_ele_iproc_jproc)
21773 
21774  } // if (jproc != my_rank)
21775 
21776  } // for (jproc < nproc)
21777 
21778  // Then the local shared haloed (invert the indexes to get the
21779  // haloed elements)
21780  const unsigned nlocal_haloed_shared_bound_ele_iproc_my_rank =
21781  new_local_halo_shared_boundary_element_pt[iproc][my_rank].size();
21782  for (unsigned e = 0;
21783  e < nlocal_haloed_shared_bound_ele_iproc_my_rank; e++)
21784  {
21785  // Get the element
21786  FiniteElement* ele_pt =
21787  new_local_halo_shared_boundary_element_pt[iproc][my_rank][e];
21788  // Get the face index
21789  const unsigned face_index =
21790  new_local_halo_shared_boundary_element_face_index[iproc][my_rank][e];
21791 
21792  // Only include the element if it is nonhalo (this may be an
21793  // old halo element that helped to indentify a shared boundary
21794  // with iproc)
21795  if (!ele_pt->is_halo())
21796  {
21797  // Add the elements to the containers
21798  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21799  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21800  } // if (!ele_pt->is_halo())
21801 
21802  } // for (e < nlocal_haloed_shared_bound_ele_iproc_my_rank)
21803 
21804  // ... and finally any additional shared boundary elements from
21805  // tmp_group1
21806  const unsigned ntmp_group1_shared_bound_ele_iproc =
21807  tmp_group1_shared_boundary_element_pt[iproc].size();
21808  for (unsigned e = 0; e < ntmp_group1_shared_bound_ele_iproc; e++)
21809  {
21810  // Get the element
21811  FiniteElement* ele_pt =
21812  tmp_group1_shared_boundary_element_pt[iproc][e];
21813  // Get the face index
21814  const unsigned face_index =
21815  tmp_group1_shared_boundary_element_face_index[iproc][e];
21816 
21817  // Add the elements to the containers
21818  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21819  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21820 
21821  } // for (e < ntmp_group1_shared_bound_ele_iproc)
21822 
21823  } // if (my_rank < iproc)
21824  // Highest processor
21825  else if (my_rank > iproc)
21826  {
21827  // Get the haloed elements first and then the elements received
21828  // from processor "jproc" but that are haloed with "iproc"
21829  // processor
21830 
21831  // Get the number of elements to copy from local elements
21832  // (invert the indexes to get the haloed elements)
21833  const unsigned nlocal_haloed_shared_bound_ele_iproc_my_rank =
21834  new_local_halo_shared_boundary_element_pt[iproc][my_rank].size();
21835  for (unsigned e = 0;
21836  e < nlocal_haloed_shared_bound_ele_iproc_my_rank; e++)
21837  {
21838  // Get the element
21839  FiniteElement* ele_pt =
21840  new_local_halo_shared_boundary_element_pt[iproc][my_rank][e];
21841  // Get the face index
21842  const unsigned face_index =
21843  new_local_halo_shared_boundary_element_face_index[iproc][my_rank][e];
21844 
21845  // Only include the element if it is nonhalo (this may be an
21846  // old halo element that helped to indentify a shared boundary
21847  // with iproc)
21848  if (!ele_pt->is_halo())
21849  {
21850  // Add the elements to the containers
21851  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21852  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21853  } // if (!ele_pt->is_halo())
21854 
21855  } // for (e < nlocal_haloed_shared_bound_ele_iproc_my_rank)
21856 
21857  for (unsigned jproc = 0; jproc < nproc; jproc++)
21858  {
21859  // Can not receive elements from itself
21860  if (jproc != my_rank)
21861  {
21862  // Then the received shared elements from "jproc" but haloed
21863  // with "iproc"
21864  const unsigned nrecvd_haloed_shared_bound_ele_jproc_iproc =
21865  new_received_haloed_shared_boundary_element_pt[jproc][iproc].size();
21866  for (unsigned e = 0;
21867  e < nrecvd_haloed_shared_bound_ele_jproc_iproc; e++)
21868  {
21869  // Get the element
21870  FiniteElement* ele_pt =
21871  new_received_haloed_shared_boundary_element_pt[jproc][iproc][e];
21872  // Get the face index
21873  const unsigned face_index =
21874  new_received_haloed_shared_boundary_element_face_index[jproc][iproc][e];
21875 
21876  // Add the elements to the containers
21877  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21878  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21879 
21880  } // for (e < nrecvd_haloed_shared_bound_ele_iproc)
21881 
21882  } // if (jproc != my_rank)
21883 
21884  } // for (jproc < nproc)
21885 
21886  // ... and finally any additional shared boundary elements from
21887  // tmp_group2
21888  const unsigned ntmp_group2_shared_bound_ele_iproc =
21889  tmp_group2_shared_boundary_element_pt[iproc].size();
21890  for (unsigned e = 0; e < ntmp_group2_shared_bound_ele_iproc; e++)
21891  {
21892  // Get the element
21893  FiniteElement* ele_pt =
21894  tmp_group2_shared_boundary_element_pt[iproc][e];
21895  // Get the face index
21896  const unsigned face_index =
21897  tmp_group2_shared_boundary_element_face_index[iproc][e];
21898 
21899  // Add the elements to the containers
21900  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21901  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21902 
21903  } // for (e < ntmp_group2_shared_bound_ele_iproc)
21904 
21905  } // else if (my_rank > iproc)
21906 
21907  } // for (iproc < nproc)
21908 
21909  // The time to sort shared boundaries
21910  if (Print_timings_level_load_balance>1)
21911  {
21912  oomph_info << "CPU for sorting shared boundaries (load balance) [8]: "
21913  <<TimingHelpers::timer()-tt_start_sort_shared_boundaries
21914  << std::endl;
21915  }
21916 
21917  // =====================================================================
21918  // END: SORT THE SHARED BOUNDARIES SO THAT THEY ARE CREATED IN THE
21919  // SAME ORDER IN THE INVOLVED PROCESSORS (A PAIR OF PROCESSORS)
21920  // =====================================================================
21921 
21922  // =====================================================================
21923  // BEGIN: CREATE THE NEW SHARED BOUNDARIES. BEFORE THE GENERATION OF
21924  // THE SHARED BOUNDARIES PUT IN A CONTAINER THOSE NONHALO ELEMENTS
21925  // THAT WILL REMAIN IN THE CURRENT PROCESSOR (BECAUSE THEIR RANK IS
21926  // THE SAME AS THE CURRENT PROCESSOR), AND THOSE ELEMENTS RECEIVED
21927  // FROM OTHER PROCESSORS. THESE SET OF ELEMENTS WILL BE USED TO
21928  // CHECK FOR POSSIBLE CONNECTIONS OF THE NEW SHARED BOUNDARIES WITH
21929  // THE ORIGINAL BOUNDARIES
21930  // =====================================================================
21931  // Finally, create the new shared boundaries
21932 
21933  // Get the time to create the new shared boundaries
21934  double tt_start_create_new_shared_boundaries=0.0;
21935  if (Print_timings_level_load_balance>1)
21936  {
21937  tt_start_create_new_shared_boundaries=TimingHelpers::timer();
21938  }
21939 
21940  // Compute the elements that will remain after deletion in the
21941  // curent processor. This is required to check if the new shared
21942  // boundaries crete a connection with any node of the elements in
21943  // the boundaries
21944 
21945  // Try to use as much information as possible
21946 
21947  // Storage for the elements in the processor
21948  std::set<FiniteElement*> element_in_processor_pt;
21949 
21950  // Loop over the old elements, those before sending/received
21951  // elements to/from other processors
21952  unsigned nh_count6 = 0;
21953  for (unsigned e = 0; e < nelement_before_load_balance; e++)
21954  {
21955  // Get the element
21956  FiniteElement* ele_pt = backed_up_ele_pt[e];
21957  // Only work with nonhalo elements
21958  if (!(ele_pt->is_halo()))
21959  {
21960  // Is the element part of the new domain
21961  if (target_domain_for_local_non_halo_element[nh_count6++] == my_rank)
21962  {
21963  // Add the element to the set of elements in the processor
21964  element_in_processor_pt.insert(ele_pt);
21965 
21966  }
21967 
21968  } // if (!(ele_pt->is_halo()))
21969 
21970  } // for (e < nelement_before_load_balance)
21971 
21972  // Now include the received elements from the other processors
21973  // Loop over the processors
21974  for (unsigned iproc = 0; iproc < nproc; iproc++)
21975  {
21976  // No elements received from myself
21977  if (iproc != my_rank)
21978  {
21979  // Get the number of received elements with the "iproc"
21980  // processor
21981  const unsigned n_received_ele = received_elements_pt[iproc].size();
21982  for (unsigned ie = 0; ie < n_received_ele; ie++)
21983  {
21984  // Get the ie-th received element from processor iproc
21985  FiniteElement* ele_pt = received_elements_pt[iproc][ie];
21986 
21987  // Include it in the set of elements in the processor
21988  element_in_processor_pt.insert(ele_pt);
21989 
21990  } // for (ie < nreceived_ele)
21991 
21992  } // if (iproc != my_rank)
21993 
21994  } // for (iproc < nproc)
21995 
21996  // Now create the shared boundaries
21997  create_new_shared_boundaries(element_in_processor_pt,
21998  new_shared_boundary_element_pt,
21999  new_shared_boundary_element_face_index);
22000 
22001  // The time to create the new shared boundaries
22002  if (Print_timings_level_load_balance>1)
22003  {
22004  oomph_info << "CPU for creating new shared boundaries (load balance) [9]: "
22005  <<TimingHelpers::timer()-tt_start_create_new_shared_boundaries
22006  << std::endl;
22007  }
22008 
22009  // =====================================================================
22010  // END: CREATE THE NEW SHARED BOUNDARIES. BEFORE THE GENERATION OF
22011  // THE SHARED BOUNDARIES PUT IN A CONTAINER THOSE NONHALO ELEMENTS
22012  // THAT WILL REMAIN IN THE CURRENT PROCESSOR (BECAUSE THEIR RANK IS
22013  // THE SAME AS THE CURRENT PROCESSOR), AND THOSE ELEMENTS RECEIVED
22014  // FROM OTHER PROCESSORS. THESE SET OF ELEMENTS WILL BE USED TO
22015  // CHECK FOR POSSIBLE CONNECTIONS OF THE NEW SHARED BOUNDARIES WITH
22016  // THE ORIGINAL BOUNDARIES
22017  // =====================================================================
22018 
22019  // =====================================================================
22020  // BEGIN: DELETE THE ELEMENTS NO LONGER BELONGING TO THE DOMAIN,
22021  // INCLUDING HALO ELEMENTS. ADD THE KEPT ELEMENTS TO THE MESH AND
22022  // THE RECEIVED ELEMENTS FROM OTHER PROCESSORS
22023  // =====================================================================
22024 
22025  // Get the time to delete elements no longer belonging to the
22026  // processor
22027  double tt_start_delete_elements=0.0;
22028  if (Print_timings_level_load_balance>1)
22029  {
22030  tt_start_delete_elements=TimingHelpers::timer();
22031  }
22032 
22033  // Once computed the new shared boundaries delete the elements that
22034  // no longer belong to the processor (including the old halo
22035  // elements)
22036 
22037  // The procedure is similar to the one performed at the distribution
22038  // stage (src/generic/mesh.cc -- distribute() method)
22039 
22040  // Clean the storage for halo(ed) elements/nodes
22041  this->Halo_node_pt.clear();
22042  this->Root_halo_element_pt.clear();
22043 
22044  this->Haloed_node_pt.clear();
22045  this->Root_haloed_element_pt.clear();
22046 
22047  // Mark all the nodes as obsolete
22048  const unsigned nnodes = this->nnode();
22049  for (unsigned j = 0; j < nnodes; j++)
22050  {
22051  this->node_pt(j)->set_obsolete();
22052  }
22053 
22054  // Flush the mesh storage
22055  this->flush_element_storage();
22056 
22057  // Delete any storage of external elements and nodes
22058  this->delete_all_external_storage();
22059 
22060  // Clear external storage
22061  this->External_halo_node_pt.clear();
22062  this->External_halo_element_pt.clear();
22063 
22064  this->External_haloed_node_pt.clear();
22065  this->External_haloed_element_pt.clear();
22066 
22067  // Keep track of the deleted elements
22068  Vector<FiniteElement*> deleted_elements;
22069 
22070  // Delete the elements that no longer belong to the processor
22071  unsigned nh_count7 = 0;
22072  for (unsigned e = 0; e < nelement_before_load_balance; e++)
22073  {
22074  FiniteElement* ele_pt = backed_up_ele_pt[e];
22075  // Only work with nonhalo elements
22076  if (!(ele_pt->is_halo()))
22077  {
22078  if (target_domain_for_local_non_halo_element[nh_count7++] == my_rank)
22079  {
22080  // Add the element to the mesh
22081  this->add_element_pt(ele_pt);
22082  // Get the number of nodes on the element
22083  const unsigned nele_nodes = ele_pt->nnode();
22084  // Loop over the nodes of the element
22085  for (unsigned j = 0; j < nele_nodes; j++)
22086  {
22087  // Mark the node as non-obsolete
22088  ele_pt->node_pt(j)->set_non_obsolete();
22089  } // for (j < nele_nodes)
22090 
22091  } // The element belongs to the domain
22092  else
22093  {
22094  // Delete the element, but keep track of it
22095  deleted_elements.push_back(ele_pt);
22096  // Delete and point to null
22097  delete ele_pt;
22098  ele_pt = 0;
22099  }
22100 
22101  } // if (!(ele_pt->is_halo()))
22102  else
22103  {
22104  // If the element is halo, delete if but keep track of it
22105  deleted_elements.push_back(ele_pt);
22106  // Delete and point to null
22107  delete ele_pt;
22108  ele_pt = 0;
22109  }
22110 
22111  } // for (e < nelement_before_load_balance)
22112 
22113  // Now add the received elements from each processor
22114  for (unsigned iproc = 0; iproc < nproc; iproc++)
22115  {
22116  if (iproc != my_rank)
22117  {
22118  // Get the number of received elements with the "iproc"
22119  // processor
22120  const unsigned nreceived_ele = received_elements_pt[iproc].size();
22121  for (unsigned ie = 0; ie < nreceived_ele; ie++)
22122  {
22123  // Get the element and add it to the mesh
22124  FiniteElement* ele_pt = received_elements_pt[iproc][ie];
22125  // Add the element to the mesh
22126  this->add_element_pt(ele_pt);
22127  // Get the number of nodes on the element
22128  const unsigned nele_nodes = ele_pt->nnode();
22129  // Loop over the nodes of the element
22130  for (unsigned j = 0; j < nele_nodes; j++)
22131  {
22132  // Mark the node as non-obsolete
22133  ele_pt->node_pt(j)->set_non_obsolete();
22134  } // for (j < nele_nodes)
22135 
22136  } // for (ie < nreceived_ele)
22137 
22138  } // if (iproc != my_rank)
22139 
22140  } // for (iproc < nproc)
22141 
22142  // Now remove the obsolete nodes
22143  this->prune_dead_nodes();
22144 
22145  // The time to delete elements no longer belonging to the processor
22146  if (Print_timings_level_load_balance>1)
22147  {
22148  oomph_info << "CPU for deleting elements no longer belonging to this processor (load balance) [10]: "
22149  <<TimingHelpers::timer()-tt_start_delete_elements
22150  << std::endl;
22151  }
22152 
22153  // =====================================================================
22154  // END: DELETE THE ELEMENTS NO LONGER BELONGING TO THE DOMAIN,
22155  // INCLUDING HALO ELEMENTS. ADD THE KEPT ELEMENTS TO THE MESH AND
22156  // THE RECEIVED ELEMENTS FROM OTHER PROCESSORS
22157  // =====================================================================
22158 
22159  // =====================================================================
22160  // BEGIN: REESTABLISH THE HALO(ED) SCHEME, ATTACH HALO ELEMENTS
22161  // (HALO NODES INCLUDED) TO THE NEW MESH (AFTER LOAD BALANCING)
22162  // RESTORE THE BOUNDARY ELEMENTS SCHEME AND THE NUMBER OF SEGMENTS
22163  // ON EACH BOUNDARY
22164  // =====================================================================
22165 
22166  // Get the time to re-establish the halo(ed) information
22167  double tt_start_re_etablish_halo_ed_info=0.0;
22168  if (Print_timings_level_load_balance>1)
22169  {
22170  tt_start_re_etablish_halo_ed_info=TimingHelpers::timer();
22171  }
22172 
22173  // Prepare the data to re-establish the halo(ed) scheme
22174 
22175  // Sort the nodes on the new shared boundaries so that they have the
22176  // same order on all processors
22177  this->sort_nodes_on_shared_boundaries();
22178 
22179  // Before re-establish the halo and haloed elements save the number
22180  // of current elements in the boundaries, this will be useful to
22181  // re-establish the boundary elements. Notice that there may be
22182  // boundary elements with null pointers, since the element may no
22183  // longer belong to the current processor
22184  const unsigned tmp_nboundary = this->nboundary();
22185  Vector<unsigned> ntmp_boundary_elements(tmp_nboundary);
22186 
22187  // If there are regions, save the number of boundary-region elements
22188  Vector<Vector<unsigned> > ntmp_boundary_elements_in_region(tmp_nboundary);
22189  // Are there regions?
22190  const unsigned n_regions = this->nregion();
22191 
22192  // Loop over the boundaries
22193  for (unsigned ib = 0; ib < tmp_nboundary; ib++)
22194  {
22195  // Get the number of boundary elements
22196  ntmp_boundary_elements[ib] = this->nboundary_element(ib);
22197 
22198  // Resize the container
22199  ntmp_boundary_elements_in_region[ib].resize(n_regions);
22200 
22201  // Loop over the regions
22202  for (unsigned rr = 0 ; rr < n_regions; rr++)
22203  {
22204  // Get the region id
22205  const unsigned region_id =
22206  static_cast<unsigned>(this->region_attribute(rr));
22207 
22208  // Store the number of element in the region (notice we are
22209  // using the region index not the region id to refer to the
22210  // region)
22211  ntmp_boundary_elements_in_region[ib][rr] =
22212  this->nboundary_element_in_region(ib, region_id);
22213 
22214  } // for (rr < n_regions)
22215 
22216  } // for (ib < tmp_nboundary)
22217 
22218  // Re-establish the halo(ed) scheme
22219  this->reset_halo_haloed_scheme();
22220 
22221  // Get the number of elements in the mesh after load balance
22222  const unsigned nelement_after_load_balance = this->nelement();
22223 
22224  // We need to reset boundary elements because we need to get rid of
22225  // the old boundary elements and stay only with the new ones
22226  this->reset_boundary_element_info(ntmp_boundary_elements,
22227  ntmp_boundary_elements_in_region,
22228  deleted_elements);
22229 
22230  // There is no need to re-set boundary coordinates since the
22231  // load-balanced mesh already has the correct information (the
22232  // boundary coordinate for each node was sent with the node
22233  // information)
22234 
22235  // We need to re-compute the number of segments on each boundary
22236  // after load balance. It may be possible that the boundary is now
22237  // split in more segments, or that previous gaps between the
22238  // segments have now dissapeared because the received elements
22239  // filled those gaps
22240 
22241  // In order to re-set the number of segments it is required to get
22242  // the face elements, attach them to create a contiguous
22243  // representation of the boundary (in segments possibly) and then
22244  // counter the number of segments. This can only be done after
22245  // restoring the boundary elements scheme (which has been done
22246  // above)
22247 
22248  // Set the number of segments for the boundaries with geom objects
22249  // associated. The correct value is not on the original mesh since
22250  // it is computed only when calling then
22251  // setup_boundary_coordinates() method (called only for those
22252  // boundaries with no geom object associated)
22253  for (unsigned b = 0; b < tmp_nboundary; b++)
22254  {
22255  if (this->boundary_geom_object_pt(b)!=0)
22256  {
22257  // Clear the boundary segment nodes storage
22258  this->flush_boundary_segment_node(b);
22259 
22260  // Dummy vector of nodes on segments
22261  Vector<Vector<Node*> > dummy_segment_node_pt;
22262 
22263  // Compute the new number of segments in the boundary
22264  get_boundary_segment_nodes_helper(b, dummy_segment_node_pt);
22265 
22266  // Get the number of segments from the vector of nodes
22267  const unsigned nsegments = dummy_segment_node_pt.size();
22268 
22269  // Set the number of segments for the storing of the nodes
22270  // associated to the segments
22271  this->set_nboundary_segment_node(b, nsegments);
22272  } // if (this->boundary_geom_object_pt(b)!=0)
22273 
22274  } // for (b < n_boundary)
22275 
22276  // The time to re-establish the halo(ed) information
22277  if (Print_timings_level_load_balance>1)
22278  {
22279  oomph_info << "CPU for re-establishing halo(ed) information (load balance) [11]: "
22280  <<TimingHelpers::timer()-tt_start_re_etablish_halo_ed_info
22281  << std::endl;
22282  }
22283 
22284  // =====================================================================
22285  // END: REESTABLISH THE HALO(ED) SCHEME, ATTACH HALO ELEMENTS (HALO
22286  // NODES INCLUDED) TO THE NEW MESH (AFTER LOAD BALANCING) RESTORE
22287  // THE BOUNDARY ELEMENTS SCHEME AND THE NUMBER OF SEGMENTS ON EACH
22288  // BOUNDARY
22289  // =====================================================================
22290 
22291  if (Print_timings_level_load_balance>1)
22292  {
22293  oomph_info <<"CPU for load balance [n_ele_before="
22294  <<nelement_before_load_balance<<", n_ele_after="
22295  <<nelement_after_load_balance<<"]: "
22296  <<TimingHelpers::timer()-t_start_overall_load_balance
22297  << std::endl;
22298  }
22299 
22300  oomph_info << "Load balance (unstructured mesh) [END]" << std::endl;
22301 
22302  }
22303 
22304  //======================================================================
22305  /// Use the first and second group of elements to find the
22306  /// intersection between them to get the shared boundary
22307  /// elements from the first and second group
22308  //======================================================================
22309  template <class ELEMENT>
22312  const Vector<FiniteElement*> &first_element_pt,
22313  const Vector<FiniteElement*> &second_element_pt,
22314  Vector<FiniteElement*> &first_shared_boundary_element_pt,
22315  Vector<unsigned> &first_shared_boundary_element_face_index,
22316  Vector<FiniteElement*> &second_shared_boundary_element_pt,
22317  Vector<unsigned> &second_shared_boundary_element_face_index)
22318  {
22319  // 1) Compare their faces (nodes) and if they match then they are
22320  // part of a shared boundary
22321  // 2) Save the first and second group of elements that give rise to
22322  // the shared boundary, also include the face index
22323 
22324  // Get the number of elements on the first group
22325  const unsigned nfirst_element = first_element_pt.size();
22326  // Loop over the elements in the first group
22327  for (unsigned ef = 0; ef < nfirst_element; ef++)
22328  {
22329  // Get the element
22330  FiniteElement* fele_pt = first_element_pt[ef];
22331  // Check if the element is halo
22332  bool first_ele_is_halo = false;
22333  if (fele_pt->is_halo())
22334  {
22335  first_ele_is_halo = true;
22336  }
22337  // Get each of the faces
22338  for (unsigned ifface = 0; ifface < 3; ifface++)
22339  {
22340  Vector<Node*> first_face(2);
22341  if (ifface == 0)
22342  {
22343  first_face[0] = fele_pt->node_pt(1);
22344  first_face[1] = fele_pt->node_pt(2);
22345  }
22346  else if (ifface == 1)
22347  {
22348  first_face[0] = fele_pt->node_pt(2);
22349  first_face[1] = fele_pt->node_pt(0);
22350  }
22351  else if (ifface == 2)
22352  {
22353  first_face[0] = fele_pt->node_pt(0);
22354  first_face[1] = fele_pt->node_pt(1);
22355  }
22356 
22357  // Now check each of the faces with the faces on the second
22358  // elements
22359 
22360  // Get the number of elements on the second group
22361  const unsigned nsecond_element = second_element_pt.size();
22362  // Loop over the elements in the second group
22363  for (unsigned es = 0; es < nsecond_element; es++)
22364  {
22365  // Get the element
22366  FiniteElement* sele_pt = second_element_pt[es];
22367  // Check if the element is halo
22368  bool second_ele_is_halo = false;
22369  if (sele_pt->is_halo())
22370  {
22371  second_ele_is_halo = true;
22372  }
22373  // Now check whether both elements are halo, if that is the
22374  // case then we go for the next elements. We can not look for
22375  // shared boundaries between halo elements since other
22376  // processors, those with the nonhalo counterpart of the
22377  // elements, are in charge of creating those shared boundaries
22378  if (!(first_ele_is_halo && second_ele_is_halo))
22379  {
22380  // Get each of the faces
22381  for (unsigned isface = 0; isface < 3; isface++)
22382  {
22383  Vector<Node*> second_face(2);
22384  if (isface == 0)
22385  {
22386  second_face[0] = sele_pt->node_pt(1);
22387  second_face[1] = sele_pt->node_pt(2);
22388  }
22389  else if (isface == 1)
22390  {
22391  second_face[0] = sele_pt->node_pt(2);
22392  second_face[1] = sele_pt->node_pt(0);
22393  }
22394  else if (isface == 2)
22395  {
22396  second_face[0] = sele_pt->node_pt(0);
22397  second_face[1] = sele_pt->node_pt(1);
22398  }
22399 
22400  // Now check for any intersection among first and second
22401  // faces
22402  if (first_face[0] == second_face[0] &&
22403  first_face[1] == second_face[1])
22404  {
22405  // Save the elements on the corresponding containers
22406  first_shared_boundary_element_pt.push_back(fele_pt);
22407  // .. and the face index
22408  first_shared_boundary_element_face_index.push_back(ifface);
22409 
22410  // Save the elements on the corresponding containers
22411  second_shared_boundary_element_pt.push_back(sele_pt);
22412  // .. and the face index
22413  second_shared_boundary_element_face_index.push_back(isface);
22414 
22415  // Break the loop over the faces of the first elements
22416  // and the first elements, we need to continue looking
22417  // on the next face of the first elements
22418 
22419  // Increase the indexes to force breaking the loop
22420  isface = 3;
22421  es = nsecond_element;
22422 
22423  }
22424  // Check for intersection with the reversed case too
22425  else if (first_face[0] == second_face[1] &&
22426  first_face[1] == second_face[0])
22427  {
22428  // Save the elements on the corresponding containers
22429  first_shared_boundary_element_pt.push_back(fele_pt);
22430  // .. and the face index
22431  first_shared_boundary_element_face_index.push_back(ifface);
22432 
22433  // Save the elements on the corresponding containers
22434  second_shared_boundary_element_pt.push_back(sele_pt);
22435  // .. and the face index
22436  second_shared_boundary_element_face_index.push_back(isface);
22437 
22438  // Break the loop over the faces of the first elements
22439  // and the first elements, we need to continue looking
22440  // on the next face of the first elements
22441 
22442  // Increase the indexes to force breaking the loop
22443  isface = 3;
22444  es = nsecond_element;
22445  }
22446 
22447  } // for (isface < 3)
22448 
22449  } // if (!(first_ele_is_halo && second_ele_is_halo))
22450 
22451  } // for (es < nsecond_element)
22452 
22453  } // for (ifface < 3)
22454 
22455  } // for (ef < nfirst_element)
22456 
22457  }
22458 
22459  //======================================================================
22460  /// \short Creates the new shared boundaries, this method is also in
22461  /// charge of computing the shared boundaries ids of each processor
22462  /// and send that info. to all the processors
22463  //======================================================================
22464  template <class ELEMENT>
22466  create_new_shared_boundaries(std::set<FiniteElement*>
22467  &element_in_processor_pt,
22469  &new_shared_boundary_element_pt,
22471  &new_shared_boundary_element_face_index)
22472  {
22473  // Get the number of processors
22474  const unsigned nproc = this->communicator_pt()->nproc();
22475  // Get the rank of the current processor
22476  const unsigned my_rank = this->communicator_pt()->my_rank();
22477 
22478  // ================================================================
22479  // BEGIN: GET THE SHARED BOUNDARY FACE ELEMENTS FROM THE SHARED
22480  // BOUNDARY ELEMENTS, AND ASSIGN A ROOT EDGE TO EACH FACE
22481  // ELEMENT. AVOID THE CREATION OF FACE ELEMENTS THAT REPRESENT THE
22482  // SAME EDGE (INTERNAL BOUNDARIES)
22483  // ================================================================
22484 
22485  // Get the time to get edges from shared boundary face elements
22486  double tt_start_get_edges_from_shd_bnd_face_ele=0.0;
22487  if (Print_timings_level_load_balance>2)
22488  {
22489  tt_start_get_edges_from_shd_bnd_face_ele=TimingHelpers::timer();
22490  }
22491 
22492  // Face elements that create the shared boundaries (unsorted)
22493  Vector<Vector<FiniteElement*> > tmp_unsorted_face_ele_pt(nproc);
22494  // The elements from where the face element was created
22495  Vector<Vector<FiniteElement*> > tmp_unsorted_ele_pt(nproc);
22496  // The face index of the bulk element from where was created the
22497  // face element
22498  Vector<Vector<int> > tmp_unsorted_face_index_ele(nproc);
22499 
22500  // Store the current edges lying on boundaries (this will help for
22501  // any edge of a shared boundary lying on an internal boundary)
22502  std::map<std::pair<Node*, Node*>, unsigned> elements_edges_on_boundary;
22503 
22504  // Compute the edges on the other boundaries
22505  this->get_element_edges_on_boundary(elements_edges_on_boundary);
22506 
22507  // Mark those edges (pair of nodes overlapped by a shared boundary)
22508  std::map<std::pair<Node*,Node*>, bool> overlapped_edge;
22509 
22510  // Associate every found edge (face element) on the shared boundary
22511  // with an original boundary only if the edge (face element) lies
22512  // (overlaps) on an original boundary, it may happen only for
22513  // internal boundaries
22514  Vector<Vector<int> > tmp_edge_boundary(nproc);
22515 
22516  // Get the face elements from the shared boundary elements with in
22517  // each processor
22518  for (unsigned iproc = 0; iproc < nproc; iproc++)
22519  {
22520  // There are no shared boundary elements with myself
22521  if (iproc != my_rank)
22522  {
22523  // Get the number of shared boundary elements with in "iproc"
22524  // processor
22525  const unsigned n_shared_bound_ele =
22526  new_shared_boundary_element_pt[iproc].size();
22527 
22528  // Avoid to create repeated face elements, compare the nodes on
22529  // the edges of the face elements
22530  Vector<std::pair<Node*, Node*> > done_faces;
22531 
22532  // Count the number of repeated faces
22533  unsigned nrepeated_faces = 0;
22534 
22535  // Loop over the shared boundary elements with the iproc
22536  // processor
22537  for (unsigned iele = 0; iele < n_shared_bound_ele; iele++)
22538  {
22539  // Get the bulk element
22540  FiniteElement* bulk_ele_pt =
22541  new_shared_boundary_element_pt[iproc][iele];
22542 
22543  // Get the face index
22544  int face_index =
22545  static_cast<int>(new_shared_boundary_element_face_index[iproc][iele]);
22546 
22547  // Create the face element
22548  FiniteElement* tmp_ele_pt =
22549  new DummyFaceElement<ELEMENT> (bulk_ele_pt, face_index);
22550 
22551  // Before adding the face element to the vector check that is
22552  // not has been previously created
22553  bool done_face = false;
22554 
22555  // Get the number of nodes on the face element and get the first
22556  // and last node
22557  const unsigned nnode_face_ele = tmp_ele_pt->nnode();
22558  Node* first_face_node_pt = tmp_ele_pt->node_pt(0);
22559  Node* last_face_node_pt = tmp_ele_pt->node_pt(nnode_face_ele - 1);
22560 
22561  // Get the number of already done face elements
22562  const unsigned ndone_faces = done_faces.size();
22563  // Loop over the already visited face elements
22564  for (unsigned n = 0; n < ndone_faces; n++)
22565  {
22566  Node* first_done_face_node_pt = done_faces[n].first;
22567  Node* second_done_face_node_pt = done_faces[n].second;
22568  if (first_face_node_pt == first_done_face_node_pt &&
22569  last_face_node_pt == second_done_face_node_pt)
22570  {
22571  done_face = true;
22572  nrepeated_faces++;
22573  break;
22574  }
22575  // Check for the reversed case
22576  else if (first_face_node_pt == second_done_face_node_pt &&
22577  last_face_node_pt == first_done_face_node_pt)
22578  {
22579  done_face = true;
22580  nrepeated_faces++;
22581  break;
22582  }
22583 
22584  } // for (n < ndone_faces)
22585 
22586  // Only include the faces that are not repeated
22587  if (!done_face)
22588  {
22589  // Add the face element in the vector
22590  tmp_unsorted_face_ele_pt[iproc].push_back(tmp_ele_pt);
22591  // Add the bulk element to the vector
22592  tmp_unsorted_ele_pt[iproc].push_back(bulk_ele_pt);
22593  // Add the face index to the vector
22594  tmp_unsorted_face_index_ele[iproc].push_back(face_index);
22595  // Include the nodes in the done nodes vector
22596  std::pair<Node*, Node*> tmp_edge =
22597  std::make_pair(first_face_node_pt, last_face_node_pt);
22598  // Push the edge
22599  done_faces.push_back(tmp_edge);
22600 
22601  // Associate the face element with a boundary (if that is
22602  // the case)
22603  int edge_boundary_id = -1;
22604  std::map<std::pair<Node*,Node*>, unsigned >::iterator it;
22605  it = elements_edges_on_boundary.find(tmp_edge);
22606  // If the edges lie on a boundary then get the boundary id
22607  // on which the edges lie
22608  if (it != elements_edges_on_boundary.end())
22609  {
22610  // Assign the internal boundary id associated with the
22611  // edge
22612  edge_boundary_id = (*it).second;
22613  // Mark the edge as overlapped
22614  overlapped_edge[tmp_edge] = true;
22615  // Also include the reversed version of the edge
22616  std::pair<Node*, Node*> rev_tmp_edge =
22617  std::make_pair(last_face_node_pt, first_face_node_pt);
22618  // Mark the reversed version of the edge as overlapped
22619  overlapped_edge[rev_tmp_edge] = true;
22620  }
22621  else
22622  {
22623  // Look for the reversed version
22624  std::pair<Node*,Node*> rtmp_edge =
22625  std::make_pair(last_face_node_pt, first_face_node_pt);
22626  it = elements_edges_on_boundary.find(rtmp_edge);
22627  if (it != elements_edges_on_boundary.end())
22628  {
22629  // Assign the internal boundary id associated with the
22630  // edge
22631  edge_boundary_id = (*it).second;
22632  // Mark the edge as overlapped
22633  overlapped_edge[rtmp_edge] = true;
22634  // Mark the reversed version (normal) of the edge as
22635  // overlapped
22636  overlapped_edge[tmp_edge] = true;
22637  }
22638  }
22639  // Associate the edge with a boundary
22640  tmp_edge_boundary[iproc].push_back(edge_boundary_id);
22641  } // if (!done_face)
22642  else
22643  {
22644  // Delete the repeated face elements
22645  delete tmp_ele_pt;
22646  tmp_ele_pt = 0;
22647  }
22648 
22649  } // for (iele < n_shared_bound_ele)
22650 
22651  } // if (iproc != my_rank)
22652 
22653  } // for (iproc < nproc)
22654 
22655  // The time to get edges from shared boundary face elements
22656  if (Print_timings_level_load_balance>2)
22657  {
22658  oomph_info << "CPU for getting edges from shared boundary face elements (load balance) [9.1]: "
22659  <<TimingHelpers::timer()-tt_start_get_edges_from_shd_bnd_face_ele
22660  << std::endl;
22661  }
22662 
22663  // ================================================================
22664  // END: GET THE SHARED BOUNDARY FACE ELEMENTS FROM THE SHARED
22665  // BOUNDARY ELEMENTS, AND ASSIGN A ROOT EDGE TO EACH FACE
22666  // ELEMENT. AVOID THE CREATION OF FACE ELEMENTS THAT REPRESENT THE
22667  // SAME EDGE (INTERNAL BOUNDARIES)
22668  // ================================================================
22669 
22670  // ================================================================
22671  // BEGIN: BEFORE SORTING THE SHARED FACE ELEMENTS AND ITS ASSOCIATED
22672  // DATA, WE NEED TO ENSURE THAT THEY APPEAR (OR ARE STORED) IN THE
22673  // SAME ORDER IN BOTH OF THE PROCESSORS THAT CREATED THEM. WE USE
22674  // THE BOTTOM-LEFT NODE OF EACH FACE ELEMENT TO STORE THEM IN THE
22675  // SAME ORDER IN BOTH PROCESSORS. ALSO ENSURE THAT THE FACE ELEMENTS
22676  // AGREE WITH THE FIRST AND LAST NODE IN ALL PROCESSORS
22677  // ================================================================
22678 
22679  // Get the time to sort shared face elements
22680  double tt_start_sort_shared_face_elements=0.0;
22681  if (Print_timings_level_load_balance>2)
22682  {
22683  tt_start_sort_shared_face_elements=TimingHelpers::timer();
22684  }
22685 
22686  // -----------------------------------------------------------------
22687  // Before continuing we need to ensured that the face elements are
22688  // stored in the same order in all processors. Sort them starting
22689  // from the face element with the bottom-left node coordinate
22690 
22691  // Face elements that create the shared boundaries (unsorted)
22692  Vector<Vector<FiniteElement*> > unsorted_face_ele_pt(nproc);
22693  // The elements from where the face element was created
22694  Vector<Vector<FiniteElement*> > unsorted_ele_pt(nproc);
22695  // The face index of the bulk element from where was created the
22696  // face element
22697  Vector<Vector<int> > unsorted_face_index_ele(nproc);
22698  // Associate every found edge on the shared boundary with an
22699  // original boundary only if the edge lies on an original boundary,
22700  // it may happen only for internal boundaries
22701  Vector<Vector<int> > edge_boundary(nproc);
22702 
22703  // For each face element, mark if the element should be considered
22704  // in its inverted way to fullfill with the bottom-left node to be
22705  // the first (left) node. First get the status of each element and
22706  // when they get sorted copy the values across
22707  std::vector<std::vector<bool> > tmp_treat_as_inverted(nproc);
22708  // Vector to store the status of the sorted face elements based on
22709  // the bottom-left condition
22710  std::vector<std::vector<bool> > treat_as_inverted(nproc);
22711 
22712  // Get the bottom-left node of each face element and sort them
22713  // starting from the face element with the bottom-left node
22714 
22715  // Loop over the processors
22716  for (unsigned iproc = 0; iproc < nproc; iproc++)
22717  {
22718  // There are no shared face elements with myself
22719  if (iproc != my_rank)
22720  {
22721  // Get the number of unsorted face elements
22722  const unsigned n_face_ele = tmp_unsorted_face_ele_pt[iproc].size();
22723  // Store the centroid of the face element. Perform the sorting
22724  // based on the bottom-left centroid of each face element
22725  Vector<Vector<double> > centroid_vertices(n_face_ele);
22726 
22727  // Resize the storage for the treating as inverted face element
22728  // storage
22729  tmp_treat_as_inverted[iproc].resize(n_face_ele);
22730 
22731  // Loop over the face elements associated with the iproc
22732  // processor
22733  for (unsigned e = 0; e < n_face_ele; e++)
22734  {
22735  // Get the face element
22736  FiniteElement* face_ele_pt = tmp_unsorted_face_ele_pt[iproc][e];
22737  // Get the number of nodes of the face element
22738  const unsigned n_node = face_ele_pt->nnode();
22739  Vector<double> bottom_left(2);
22740  // Assign as the bottom-left node the first node
22741  // Get the node
22742  Node* node_pt = face_ele_pt->node_pt(0);
22743  bottom_left[0] = node_pt->x(0);
22744  bottom_left[1] = node_pt->x(1);
22745  // Set as not treat as inverted element
22746  tmp_treat_as_inverted[iproc][e] = false;
22747  // Loop over the nodes to get the bottom-left vertex of all
22748  // the nodes
22749  for (unsigned n = 1; n < n_node; n++)
22750  {
22751  // Get the node
22752  Node* node_pt = face_ele_pt->node_pt(n);
22753  if (node_pt->x(1) < bottom_left[1])
22754  {
22755  bottom_left[0] = node_pt->x(0);
22756  bottom_left[1] = node_pt->x(1);
22757  // The first node is no longer the bottom-left node, we
22758  // need to treat the element as inverted
22759  tmp_treat_as_inverted[iproc][e] = true;
22760  } // if (node_pt->x(1) < bottom_left[1])
22761  else if (node_pt->x(1) == bottom_left[1])
22762  {
22763  if (node_pt->x(0) < bottom_left[0])
22764  {
22765  bottom_left[0] = node_pt->x(0);
22766  bottom_left[1] = node_pt->x(1);
22767  // The first node is no longer the bottom-left node, we
22768  // need to treat the element as inverted
22769  tmp_treat_as_inverted[iproc][e] = true;
22770  } // if (node_pt->x(0) < bottom_left[0])
22771  } // else if (node_pt->x(1) == bottom_left[1])
22772 
22773  } // for (n < n_node
22774 
22775  // Resize the container
22776  centroid_vertices[e].resize(2);
22777  // Add the centroid of the face element
22778  centroid_vertices[e][0] =
22779  (face_ele_pt->node_pt(0)->x(0) +
22780  face_ele_pt->node_pt(n_node-1)->x(0))*0.5;
22781  centroid_vertices[e][1] =
22782  (face_ele_pt->node_pt(0)->x(1) +
22783  face_ele_pt->node_pt(n_node-1)->x(1))*0.5;
22784 
22785  } // for (e < n_face_ele)
22786 
22787  // Sort the face elements based on their bottom-left node
22788  unsigned n_sorted_bottom_left = 0;
22789  // Keep track of the already sorted face elements
22790  std::vector<bool> done_face(n_face_ele, false);
22791 
22792  // Loop until all face elements have been sorted
22793  while (n_sorted_bottom_left < n_face_ele)
22794  {
22795  // The index of the next bottom-left face element
22796  unsigned index = 0;
22797  Vector<double> current_bottom_left(2);
22798  for (unsigned e = 0; e < n_face_ele; e++)
22799  {
22800  // Get the first not done face element
22801  if (!done_face[e])
22802  {
22803  // Store the first not done
22804  current_bottom_left[0] = centroid_vertices[e][0];
22805  current_bottom_left[1] = centroid_vertices[e][1];
22806  // Set the index
22807  index = e;
22808  // Break
22809  break;
22810  } // if (!done_face[e])
22811 
22812  } // for (e < n_face_ele)
22813 
22814  // Loop over all the other nondone face elements
22815  for (unsigned e = index + 1; e < n_face_ele; e++)
22816  {
22817  // Get the first not done face element
22818  if (!done_face[e])
22819  {
22820  if (centroid_vertices[e][1] < current_bottom_left[1])
22821  {
22822  // Re-set the current bottom left vertex
22823  current_bottom_left[0] = centroid_vertices[e][0];
22824  current_bottom_left[1] = centroid_vertices[e][1];
22825  // Re-assign the index
22826  index = e;
22827  } // if (centroid_vertices[e][1] < current_bottom_left[1])
22828  else if (centroid_vertices[e][1] == current_bottom_left[1])
22829  {
22830  if (centroid_vertices[e][0] < current_bottom_left[0])
22831  {
22832  // Re-set the current bottom left vertex
22833  current_bottom_left[0] = centroid_vertices[e][0];
22834  current_bottom_left[1] = centroid_vertices[e][1];
22835  // Re-assign the index
22836  index = e;
22837  } // if (centroid_vertices[e][0] < current_bottom_left[0])
22838 
22839  } // else if (centroid_vertices[e][1] == current_bottom_left[1])
22840 
22841  } // if (!done_face[e])
22842 
22843  } // for (e < n_face_ele)
22844 
22845  // The face element
22846  unsorted_face_ele_pt[iproc].
22847  push_back(tmp_unsorted_face_ele_pt[iproc][index]);
22848  // The boundary element
22849  unsorted_ele_pt[iproc].
22850  push_back(tmp_unsorted_ele_pt[iproc][index]);
22851  // The face index
22852  unsorted_face_index_ele[iproc].
22853  push_back(tmp_unsorted_face_index_ele[iproc][index]);
22854  // The edge boundary associated to the face element
22855  edge_boundary[iproc].
22856  push_back(tmp_edge_boundary[iproc][index]);
22857  // The treat as inverted condition
22858  treat_as_inverted[iproc].
22859  push_back(tmp_treat_as_inverted[iproc][index]);
22860 
22861  // Mark the face element as sorted (done or visited)
22862  done_face[index] = true;
22863 
22864  // Increase the number of sorted bottom-left face elements
22865  n_sorted_bottom_left++;
22866 
22867  } // while (n_sorted_bottom_left < n_face_ele)
22868 
22869 #ifdef PARANOID
22870  // Get the number of face elements sorted with the bottom-left
22871  // condition
22872  const unsigned tmp_n_face_ele = unsorted_face_ele_pt[iproc].size();
22873 
22874  if (tmp_n_face_ele != n_face_ele)
22875  {
22876  std::ostringstream error_stream;
22877  error_stream
22878  << "The number of face elements before sorting them starting\n"
22879  << "from their bottom-left vertex is different from the number\n"
22880  << "of face elements after the sorting\n"
22881  << "N. ele before sorting: (" << n_face_ele << ")\n"
22882  << "N. ele after sorting: (" << tmp_n_face_ele << ")\n";
22883  throw OomphLibError(error_stream.str(),
22884  "RefineableTriangleMesh::create_new_shared_boundaries()",
22885  OOMPH_EXCEPTION_LOCATION);
22886  }
22887 #endif
22888 
22889  } // if (iproc != my_rank)
22890 
22891  } // for (iproc < nproc)
22892 
22893  // The time to sort shared face elements
22894  if (Print_timings_level_load_balance>2)
22895  {
22896  oomph_info << "CPU for sorting shared boundary face elements (load balance) [9.2]: "
22897  <<TimingHelpers::timer()-tt_start_sort_shared_face_elements
22898  << std::endl;
22899  }
22900 
22901  // ================================================================
22902  // END: SORTING THE SHARED FACE ELEMENTS AND ITS ASSOCIATED DATA, WE
22903  // NEED TO ENSURE THAT THEY APPEAR (OR ARE STORED) IN THE SAME ORDER
22904  // IN BOTH OF THE PROCESSORS THAT CREATED THEM. WE USE THE
22905  // BOTTOM-LEFT NODE OF EACH FACE ELEMENT TO STORE THEM IN THE SAME
22906  // ORDER IN BOTH PROCESSORS. ALSO ENSURE THAT THE FACE ELEMENTS
22907  // AGREE WITH THE FIRST AND LAST NODE IN ALL PROCESSORS
22908  // ================================================================
22909 
22910  // ================================================================
22911  // BEGIN: COMPUTE THE GLOBAL DEGREE (VALENCY OF EACH NODE). THE
22912  // DEGREE OF THE NODES IN THE CURRENT SHARED BOUNDARIES IS COMPUTED
22913  // FIRST, THEN THIS INFO. IS SENT TO A ROOT PROCESSOR WHICH IS IN
22914  // CHARGE OF IDENTIFY AND RE-ASSIGN THE DEGREE OF THE NODES (IF THAT
22915  // IS THE CASE)
22916  // ================================================================
22917 
22918  // Get the time to compute the valency of each node
22919  double tt_start_compute_valency_of_nodes=0.0;
22920  if (Print_timings_level_load_balance>2)
22921  {
22922  tt_start_compute_valency_of_nodes=TimingHelpers::timer();
22923  }
22924 
22925  // Stores the global-degree of each node
22926  std::map<Node*, unsigned> global_node_degree;
22927 
22928  // Get the global degree (valency) of each node
22929  compute_shared_node_degree_helper(unsorted_face_ele_pt,
22930  global_node_degree);
22931 
22932  // The time to compute the valency of each node
22933  if (Print_timings_level_load_balance>2)
22934  {
22935  oomph_info << "CPU for computing the valency of nodes (load balance) [9.3]: "
22936  <<TimingHelpers::timer()-tt_start_compute_valency_of_nodes
22937  << std::endl;
22938  }
22939 
22940  // ================================================================
22941  // END: COMPUTE THE GLOBAL DEGREE (VALENCY OF EACH NODE). THE
22942  // DEGREE OF THE NODES IN THE CURRENT SHARED BOUNDARIES IS COMPUTED
22943  // FIRST, THEN THIS INFO. IS SENT TO A ROOT PROCESSOR WHICH IS IN
22944  // CHARGE OF IDENTIFY AND RE-ASSIGN THE DEGREE OF THE NODES (IF THAT
22945  // IS THE CASE)
22946  // ================================================================
22947 
22948  // ================================================================
22949  // BEGIN: IDENTIFY THE NODES LYING ON EDGES NOT OVERLAPED BY SHARED
22950  // BOUNDARIES, IDENTIFY THE BOUNDARY TO WHICH THE EDGE CORRESPOND
22951  // ================================================================
22952 
22953  // Get the time to compute nodes on non overlapped shared boundaries
22954  double tt_start_nodes_on_non_overlapped_shd_bnd=0.0;
22955  if (Print_timings_level_load_balance>2)
22956  {
22957  tt_start_nodes_on_non_overlapped_shd_bnd=TimingHelpers::timer();
22958  }
22959 
22960  // Mark the nodes on original boundaries not overlapped by shared
22961  // boundaries
22962  std::map<unsigned, std::map<Node*, bool> >
22963  node_on_bnd_not_overlapped_by_shd_bnd;
22964 
22965  // Loop over the edges of the original boundaries
22966  for (std::map<std::pair<Node*,Node*>, unsigned>::iterator it_map =
22967  elements_edges_on_boundary.begin();
22968  it_map != elements_edges_on_boundary.end(); it_map++)
22969  {
22970  // Get the edge
22971  std::pair<Node*,Node*> edge_pair = (*it_map).first;
22972  // Is the edge overlaped by a shared boundary
22973  if (!overlapped_edge[edge_pair])
22974  {
22975  // Mark the nodes of the edge as being on an edge not overlaped
22976  // by a shared boundary on the boundary the edge is
22977  unsigned b = (*it_map).second;
22978 
22979  // Get the left node
22980  Node* left_node_pt = edge_pair.first;
22981  node_on_bnd_not_overlapped_by_shd_bnd[b][left_node_pt] = true;
22982 
22983  // Get the right node
22984  Node* right_node_pt = edge_pair.second;
22985  node_on_bnd_not_overlapped_by_shd_bnd[b][right_node_pt] = true;
22986 
22987  } // if (!overlapped_edge[edge_pair])
22988 
22989  } // Loop over edges to mark those nodes on overlaped edge by
22990  // shared boundaries
22991 
22992  // The time to compute nodes on non overlapped shared boundaries
22993  if (Print_timings_level_load_balance>2)
22994  {
22995  oomph_info << "CPU for computing nodes on non overlapped shared boundaries (load balance) [9.4]: "
22996  <<TimingHelpers::timer()-tt_start_nodes_on_non_overlapped_shd_bnd
22997  << std::endl;
22998  }
22999 
23000  // ================================================================
23001  // END: IDENTIFY THE NODES LYING ON EDGES NOT OVERLAPED BY SHARED
23002  // BOUNDARIES, IDENTIFY THE BOUNDARY TO WHICH THE EDGE CORRESPOND
23003  // ================================================================
23004 
23005  // ==================================================================
23006  // BEGIN: SORT THE SHARED BOUNDARY FACE ELEMENTS, ADD FACE ELEMENTS
23007  // TO THE LEFT OR RIGHT OF THE ROOT FACE ELEMENT. STOP ADDING WHEN
23008  // THE MOST LEFT OR MOST RIGHT ELEMENT (NODE) IS ALREADY PART OF
23009  // ANOTHER BOUNDARY (THIS MEANS THAT THE SHARED BOUNDARY THAT IS
23010  // BEING CREATED HAS A CONNECTION). ALSO REMEMBER TO CHECK FOR THE
23011  // CASE WHEN THE MOST LEFT OR MOST RIGHT NODE IS A BOUNDARY NODE OF
23012  // A BOUNDARY THAT NO LONGER EXIST IN THE DOMAIN. AT THE END OF THIS
23013  // SECTION WE WILL HAVE THE NUMBER OF SHARED BOUNDARIES OF THIS
23014  // PROCESSOR WITH OTHERS BUT NOT THE GLOBAL SHARED BOUNDARY ID
23015  // ==================================================================
23016 
23017  // Get the time to sort shared boundaries face elements to create a
23018  // continuous representation of the boundary
23019  double tt_start_join_shd_bnd_face_ele=0.0;
23020  if (Print_timings_level_load_balance>2)
23021  {
23022  tt_start_join_shd_bnd_face_ele=TimingHelpers::timer();
23023  }
23024 
23025  // Face elements that create the shared boundaries (sorted)
23026  Vector<Vector<Vector<FiniteElement*> > > sorted_face_ele_pt(nproc);
23027 
23028  // Bulk elements that create the shared boundaries (sorted)
23029  Vector<Vector<Vector<FiniteElement*> > > sorted_ele_pt(nproc);
23030 
23031  // Face indexes of the bulk elements that create the shared
23032  // boundaries (sorted)
23033  Vector<Vector<Vector<int> > > sorted_face_index_ele(nproc);
23034 
23035  // Store the edge boundary id associated with a shared boundary (if
23036  // any, this apply for shared boundaries lying on internal
23037  // boundaries, then the shared boundary is marked as overlaping an
23038  // internal boundary)
23039  Vector<Vector<int> > edge_boundary_id(nproc);
23040 
23041  // Store the connection information obtained when joining the face
23042  // elements (used for connection purposes only)
23043  Vector<Vector<Vector<int> > > sorted_connection_info(nproc);
23044 
23045  // Store the local shared boundary id associated to the elements
23046  // that will give rise to the shared boundaries (used to compute the
23047  // global shared boundary id from the local shared boundary id)
23048  Vector<Vector<unsigned> > proc_local_shared_boundary_id(nproc);
23049 
23050  // Map that associates the local shared boundary id with the list of
23051  // nodes that create it
23052  std::map<unsigned, std::list<Node*> >
23053  local_shd_bnd_id_to_sorted_list_node_pt;
23054 
23055  // Local shared bouonday id (used to locally identify the lists of
23056  // nodes that create shared boundaries, it is also useful to
23057  // identify connections with shared boundaries)
23058  unsigned local_shd_bnd_id = this->Initial_shared_boundary_id;
23059 
23060  // Sort the face elements, using the nodes at its ends
23061 
23062  // Mark the done elements
23063  std::map<FiniteElement*, bool> done_ele;
23064 
23065  // Mark the inverted elements
23066  std::map<FiniteElement*, bool> is_inverted;
23067 
23068  // Sort the face elements to get the number of shared boundaries
23069  // with in each processor
23070  for (unsigned iproc = 0; iproc < nproc; iproc++)
23071  {
23072  // No face elements with myself
23073  if (iproc != my_rank)
23074  {
23075  // Get the number of unsorted face elements with the iproc
23076  // processor
23077  const unsigned nunsorted_face_ele =
23078  unsorted_face_ele_pt[iproc].size();
23079  // Count the number of sorted face elements
23080  unsigned nsorted_face_ele = 0;
23081 
23082  // Iterate until all the face elements have been sorted
23083  while (nsorted_face_ele < nunsorted_face_ele)
23084  {
23085  // Take the first nonsorted element an use it as root element,
23086  // add elements to the left and right until no more elements
23087  // left or until a stop condition is reached (connection,
23088  // boundary node)
23089 
23090 #ifdef PARANOID
23091  // Flag to indicate if a root element was found
23092  bool found_root_element = false;
23093 #endif
23094 
23095  // Index of the found root element
23096  unsigned root_index = 0;
23097 
23098  // List that contains the sorted face elements
23099  std::list<FiniteElement*> tmp_sorted_face_ele_pt;
23100 
23101  // List that contains the sorted elements
23102  std::list<FiniteElement*> tmp_sorted_ele_pt;
23103 
23104  // List that contains the sorted face indexes of the bulk
23105  // elements
23106  std::list<int> tmp_sorted_face_index_ele;
23107 
23108  // Storing for the sorting nodes extracted from the face
23109  // elements. The sorted nodes are used to identify connections
23110  // among new shared boundaries or original boundaries
23111  std::list<Node*> tmp_sorted_nodes_pt;
23112  // Clear the storage (just in case)
23113  tmp_sorted_nodes_pt.clear();
23114 
23115  // The initial and final nodes
23116  Node* initial_node_pt = 0;
23117  Node* final_node_pt = 0;
23118 
23119  // Store the original boundary id related with the root face
23120  // element (if there is one)
23121  int root_edge_bound_id = -1;
23122 
23123  // Loop over the unsorted face elements until a root element
23124  // is found
23125  for (unsigned e = 0; e < nunsorted_face_ele; e++)
23126  {
23127  // Get a root element
23128  FiniteElement* root_ele_pt = unsorted_face_ele_pt[iproc][e];
23129  // Is the element already done?
23130  if (!done_ele[root_ele_pt])
23131  {
23132  // Get the edge boundary id associated with the edge (if
23133  // there is one)
23134  root_edge_bound_id = edge_boundary[iproc][e];
23135  // Add the face element to the list of sorted face
23136  // elements
23137  tmp_sorted_face_ele_pt.push_back(root_ele_pt);
23138  // Add the bulk element to the list of sorted elements
23139  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23140  // Add the face index to the list of sorted face index
23141  // elements
23142  tmp_sorted_face_index_ele.push_back(
23143  unsorted_face_index_ele[iproc][e]);
23144 
23145  // Get the nodes and state them as initial and final
23146  const unsigned nnodes = root_ele_pt->nnode();
23147  // Check if the face element should be treated as inverted
23148  if (!treat_as_inverted[iproc][e])
23149  {
23150  initial_node_pt = root_ele_pt->node_pt(0);
23151  final_node_pt = root_ele_pt->node_pt(nnodes-1);
23152  }
23153  else
23154  {
23155  initial_node_pt = root_ele_pt->node_pt(nnodes-1);
23156  final_node_pt = root_ele_pt->node_pt(0);
23157  }
23158  // Add both nodes to the list of sorted nodes
23159  tmp_sorted_nodes_pt.push_back(initial_node_pt);
23160  tmp_sorted_nodes_pt.push_back(final_node_pt);
23161 
23162  // Mark the element as done
23163  done_ele[root_ele_pt] = true;
23164  // Check if the face element should be treated as inverted
23165  if (!treat_as_inverted[iproc][e])
23166  {
23167  // Mark the element as not inverted
23168  is_inverted[root_ele_pt] = false;
23169  }
23170  else
23171  {
23172  // Mark the element as inverted
23173  is_inverted[root_ele_pt] = true;
23174  }
23175  // Increase the counter for sorted face elements
23176  nsorted_face_ele++;
23177  // Set the root index
23178  root_index = e;
23179 #ifdef PARANOID
23180  // Set the flag of found root element
23181  found_root_element = true;
23182 #endif
23183  // Break the loop
23184  break;
23185 
23186  } // if (!done_ele[root_ele_pt])
23187 
23188  } // for (e < nunsorted_face_ele)
23189 
23190 #ifdef PARANOID
23191  if (!found_root_element)
23192  {
23193  std::ostringstream error_stream;
23194  error_stream
23195  << "It was not possible the found the root element\n\n";
23196  throw OomphLibError(error_stream.str(),
23197  OOMPH_CURRENT_FUNCTION,
23198  OOMPH_EXCEPTION_LOCATION);
23199  }
23200 #endif
23201 
23202  // New element added. Continue adding elements -- or nodes --
23203  // to the list of shared boundary elements while a new element
23204  // has been added to the list (we have just added the root
23205  // element)
23206  bool new_element_added = true;
23207 
23208  // Similarly that in the
23209  // "create_polylines_from_halo_elements_helper() method, we
23210  // extract the nodes (in order) that will create the shared
23211  // polyline, and also check for connections with the just
23212  // added face elements (nodes)
23213 
23214  // Flags to indicate at which end (of the sorted list of
23215  // boundary elements) the element was added (left or right)
23216  bool element_added_to_the_left = false;
23217  bool element_added_to_the_right = false;
23218 
23219  // Flag to indicate that the "left" node of the element added
23220  // to the left was found to be shared with another boundary
23221  bool connection_to_the_left = false;
23222 
23223  // Flag to indicate that the "right" node of the element added
23224  // to the right was found to be shared with another boundary
23225  bool connection_to_the_right = false;
23226 
23227  // Flag to stop the adding of elements (and nodes) to the
23228  // current shared boundary (because there are connections at
23229  // both ends)
23230  bool current_polyline_has_connections_at_both_ends = false;
23231 
23232  // Store the boundary ids of the polylines to connect (only
23233  // used when the polyline was found to have a connection)
23234  // -1: Indicates no connection
23235  // -2: Indicates connection with itself
23236  // -3: Indicates no connection BUT STOP adding elements
23237  // -because the node is a boundary node whose boundary is no
23238  // -currently part of the domain. Think in one of the corner
23239  // -nodes of a triangle touchin a boundary that does no longer
23240  // -exist
23241  // Any other value: Boundary id to connect
23242  int bound_id_connection_to_the_left = -1;
23243  int bound_id_connection_to_the_right = -1;
23244 
23245  // Get the global degree of the node (notice the local degree
23246  // has been updated to global degree)
23247  const unsigned initial_node_degree =
23248  global_node_degree[initial_node_pt];
23249 
23250  // Flag to indicate we are calling the method from a load
23251  // balance sub-rutine
23252  const bool called_for_load_balance=true;
23253 
23254  // Check if the nodes of the root element have connections
23255  // ... to the left
23256  bound_id_connection_to_the_left =
23257  this->check_connections_of_polyline_nodes(
23258  element_in_processor_pt,
23259  root_edge_bound_id,
23260  overlapped_edge,
23261  node_on_bnd_not_overlapped_by_shd_bnd,
23262  tmp_sorted_nodes_pt,
23263  local_shd_bnd_id_to_sorted_list_node_pt,
23264  initial_node_degree,
23265  initial_node_pt,
23266  called_for_load_balance);
23267 
23268  // If there is a stop condition then set the corresponding
23269  // flag
23270  if (bound_id_connection_to_the_left != -1)
23271  {
23272  connection_to_the_left = true;
23273  } // if (bound_id_connection_to_the_left != -1)
23274 
23275  // Get the global degree of the node (notice the local degree
23276  // has been updated to global degree)
23277  const unsigned final_node_degree =
23278  global_node_degree[final_node_pt];
23279 
23280  // ... and to the right
23281  bound_id_connection_to_the_right =
23282  this->check_connections_of_polyline_nodes(
23283  element_in_processor_pt,
23284  root_edge_bound_id,
23285  overlapped_edge,
23286  node_on_bnd_not_overlapped_by_shd_bnd,
23287  tmp_sorted_nodes_pt,
23288  local_shd_bnd_id_to_sorted_list_node_pt,
23289  final_node_degree,
23290  final_node_pt,
23291  called_for_load_balance);
23292 
23293  // If there is a stop condition then set the corresponding
23294  // flag
23295  if (bound_id_connection_to_the_right != -1)
23296  {
23297  connection_to_the_right = true;
23298  } // if (bound_id_connection_to_the_right != -1)
23299 
23300  // If the current shared boundary has connections at both ends
23301  // then stop the adding of elements (and nodes)
23302  if (connection_to_the_left && connection_to_the_right)
23303  {current_polyline_has_connections_at_both_ends = true;}
23304 
23305  // Continue searching for more elements to add if
23306  // 1) A new element was added at the left or right of the list
23307  // 2) There are more possible elements to add
23308  // 3) The nodes at the edges of the added element (left or
23309  // right) are not part of any other previous shared
23310  // boundary
23311  while(new_element_added &&
23312  (nsorted_face_ele < nunsorted_face_ele)
23313  && !current_polyline_has_connections_at_both_ends)
23314  {
23315  // Loop over the remaining elements and try to create a
23316  // contiguous set of face elements, start looking from the
23317  // root index. Any previous element should have been already
23318  // visited
23319  for (unsigned e = root_index; e < nunsorted_face_ele; e++)
23320  {
23321  // Reset the flags for added elements, to the left and right
23322  new_element_added = false;
23323  element_added_to_the_left = false;
23324  element_added_to_the_right = false;
23325 
23326  // Get the "e"-th element on the vector
23327  FiniteElement* tmp_ele_pt = unsorted_face_ele_pt[iproc][e];
23328  // Get the boundary id associated with the edge (if any)
23329  const int edge_bound_id = edge_boundary[iproc][e];
23330  // Check if the element has been already sorted and the
23331  // related edge bound id is the same as the root edge (if
23332  // any)
23333  if (!done_ele[tmp_ele_pt]
23334  && (edge_bound_id == root_edge_bound_id))
23335  {
23336  // Get the number of nodes on the current element
23337  const unsigned nnodes = tmp_ele_pt->nnode();
23338  // Get the first and last node of the element
23339  // Check if the face element should be treated as inverted
23340  Node* first_node_pt = 0;
23341  Node* last_node_pt = 0;
23342  if (!treat_as_inverted[iproc][e])
23343  {
23344  first_node_pt = tmp_ele_pt->node_pt(0);
23345  last_node_pt = tmp_ele_pt->node_pt(nnodes-1);
23346  }
23347  else
23348  {
23349  first_node_pt = tmp_ele_pt->node_pt(nnodes-1);
23350  last_node_pt = tmp_ele_pt->node_pt(0);
23351  }
23352 
23353  // A pointer to the node at the left or right of the
23354  // just added element, the most left or the most right
23355  // node
23356  Node* new_added_node_pt = 0;
23357 
23358  // Check if the element goes to the left
23359  if (initial_node_pt == last_node_pt &&
23360  !connection_to_the_left)
23361  {
23362  // Update the initial node and the just added node
23363  new_added_node_pt = initial_node_pt = first_node_pt;
23364  // Add the most left node
23365  tmp_sorted_nodes_pt.push_front(first_node_pt);
23366  // Add the face element to the list of sorted face
23367  // elements
23368  tmp_sorted_face_ele_pt.push_front(tmp_ele_pt);
23369  // Add the bulk element to the list of sorted elements
23370  tmp_sorted_ele_pt.push_front(unsorted_ele_pt[iproc][e]);
23371  // Add the face index to the list of sorted face index
23372  // elements
23373  tmp_sorted_face_index_ele.push_front(
23374  unsorted_face_index_ele[iproc][e]);
23375  if (!treat_as_inverted[iproc][e])
23376  {
23377  // Mark the element as not inverted
23378  is_inverted[tmp_ele_pt] = false;
23379  }
23380  else
23381  {
23382  // Mark the element as inverted
23383  is_inverted[tmp_ele_pt] = true;
23384  }
23385  // Set the flag to indicate a new element was added
23386  new_element_added = true;
23387  // Set the flag to indicate the element was added to
23388  // the left
23389  element_added_to_the_left = true;
23390  }
23391  // Check if the element goes to the left (but inverted)
23392  else if (initial_node_pt == first_node_pt &&
23393  !connection_to_the_left)
23394  {
23395  // Update the initial node and the just added node
23396  new_added_node_pt = initial_node_pt = last_node_pt;
23397  // Add the most left node
23398  tmp_sorted_nodes_pt.push_front(last_node_pt);
23399  // Add the face element to the list of sorted face
23400  // elements
23401  tmp_sorted_face_ele_pt.push_front(tmp_ele_pt);
23402  // Add the bulk element to the list of sorted elements
23403  tmp_sorted_ele_pt.push_front(unsorted_ele_pt[iproc][e]);
23404  // Add the face index to the list of sorted face index
23405  // elements
23406  tmp_sorted_face_index_ele.push_front(
23407  unsorted_face_index_ele[iproc][e]);
23408  if (!treat_as_inverted[iproc][e])
23409  {
23410  // Mark the element as inverted
23411  is_inverted[tmp_ele_pt] = true;
23412  }
23413  else
23414  {
23415  // Mark the element as not inverted
23416  is_inverted[tmp_ele_pt] = false;
23417  }
23418  // Set the flag to indicate a new element was added
23419  new_element_added = true;
23420  // Set the flag to indicate the element was added to
23421  // the left
23422  element_added_to_the_left = true;
23423  }
23424  // Check if the elements goes to the right
23425  else if (final_node_pt == first_node_pt
23426  && !connection_to_the_right)
23427  {
23428  // Update the final node and the just added node
23429  new_added_node_pt = final_node_pt = last_node_pt;
23430  // Add the most right node
23431  tmp_sorted_nodes_pt.push_back(last_node_pt);
23432  // Add the face element to the list of sorted face
23433  // elements
23434  tmp_sorted_face_ele_pt.push_back(tmp_ele_pt);
23435  // Add the bulk element to the list of sorted elements
23436  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23437  // Add the face index to the list of sorted face index
23438  // elements
23439  tmp_sorted_face_index_ele.push_back(
23440  unsorted_face_index_ele[iproc][e]);
23441  if (!treat_as_inverted[iproc][e])
23442  {
23443  // Mark the element as not inverted
23444  is_inverted[tmp_ele_pt] = false;
23445  }
23446  else
23447  {
23448  // Mark the element as inverted
23449  is_inverted[tmp_ele_pt] = true;
23450  }
23451  // Set the flag to indicate a new element was added
23452  new_element_added = true;
23453  // Set the flag to indicate the element was added to
23454  // the right
23455  element_added_to_the_right = true;
23456  }
23457  // Check if the elements goes to the right (but inverted)
23458  else if (final_node_pt == last_node_pt &&
23459  !connection_to_the_right)
23460  {
23461  // Update the final node and the just added node
23462  new_added_node_pt = final_node_pt = first_node_pt;
23463  // Add the most right node
23464  tmp_sorted_nodes_pt.push_back(first_node_pt);
23465  // Add the face element to the list of sorted face
23466  // elements
23467  tmp_sorted_face_ele_pt.push_back(tmp_ele_pt);
23468  // Add the bulk element to the list of sorted elements
23469  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23470  // Add the face index to the list of sorted face index
23471  // elements
23472  tmp_sorted_face_index_ele.push_back(
23473  unsorted_face_index_ele[iproc][e]);
23474  if (!treat_as_inverted[iproc][e])
23475  {
23476  // Mark the element as inverted
23477  is_inverted[tmp_ele_pt] = true;
23478  }
23479  else
23480  {
23481  // Mark the element as not inverted
23482  is_inverted[tmp_ele_pt] = false;
23483  }
23484  // Set the flag to indicate a new elements was added
23485  new_element_added = true;
23486  // Set the flag to indicate the element was added to
23487  // the right
23488  element_added_to_the_right = true;
23489  }
23490 
23491  // Do additional stuff if the element was added
23492  if (new_element_added)
23493  {
23494  // Mark the element as done
23495  done_ele[tmp_ele_pt] = true;
23496  // Increase the counter for sorted face elements
23497  nsorted_face_ele++;
23498 
23499  // Get the global degree of the node (notice the
23500  // local degree has been updated to global degree)
23501  const unsigned new_added_node_degree =
23502  global_node_degree[new_added_node_pt];
23503 
23504  // Based on which side the element was added, look for
23505  // connections on that side
23506 
23507  // Verify for connections to the left (we need to
23508  // check for the connection variable too, since
23509  // after a connection has been done we no longer
23510  // need to verify for this condition)
23511  if (element_added_to_the_left && !connection_to_the_left)
23512  {
23513  // Check for connection
23514  bound_id_connection_to_the_left =
23515  this->check_connections_of_polyline_nodes(
23516  element_in_processor_pt,
23517  root_edge_bound_id,
23518  overlapped_edge,
23519  node_on_bnd_not_overlapped_by_shd_bnd,
23520  tmp_sorted_nodes_pt,
23521  local_shd_bnd_id_to_sorted_list_node_pt,
23522  new_added_node_degree,
23523  new_added_node_pt,
23524  called_for_load_balance);
23525 
23526  // If there is a stop condition then set the
23527  // corresponding flag
23528  if (bound_id_connection_to_the_left != -1)
23529  {
23530  connection_to_the_left = true;
23531  } // if (bound_id_connection_to_the_left != -1)
23532 
23533  } // if (node_added_to_the_left &&
23534  // !connection_to_the_left)
23535 
23536  // Verify for connections to the right (we need to
23537  // check for the connection variable too, since
23538  // after a connection has been done we no longer
23539  // need to verify for this condition)
23540  if (element_added_to_the_right && !connection_to_the_right)
23541  {
23542  // Check for connection
23543  bound_id_connection_to_the_right =
23544  this->check_connections_of_polyline_nodes(
23545  element_in_processor_pt,
23546  root_edge_bound_id,
23547  overlapped_edge,
23548  node_on_bnd_not_overlapped_by_shd_bnd,
23549  tmp_sorted_nodes_pt,
23550  local_shd_bnd_id_to_sorted_list_node_pt,
23551  new_added_node_degree,
23552  new_added_node_pt,
23553  called_for_load_balance);
23554 
23555  // If there is a stop condition then set the
23556  // corresponding flag
23557  if (bound_id_connection_to_the_right != -1)
23558  {
23559  connection_to_the_right = true;
23560  } // if (bound_id_connection_to_the_right != -1)
23561 
23562  } // if (node_added_to_the_right &&
23563  // !connection_to_the_right)
23564 
23565  // If the current shared boundary has connections at
23566  // both ends then stop the adding of elements (and
23567  // nodes)
23568  if (connection_to_the_left && connection_to_the_right)
23569  {current_polyline_has_connections_at_both_ends = true;}
23570 
23571  // Break the for (looping over unsorted face
23572  // elements) and re-start looking for more elements
23573  // that fit to the left or right
23574  break;
23575 
23576  } // if (new_element_added)
23577 
23578  } // if (!done_ele[tmp_ele_pt])
23579 
23580  } // for (e < nunsorted_face_ele)
23581 
23582  } // while(new_element_added &&
23583  // (nsorted_face_ele < nunsorted_face_ele)
23584  // && !current_polyline_has_connections_at_both_ends)
23585 
23586  // ------------------------------------------------------------
23587  // Before assigning a local shared boundary id to the list of
23588  // nodes and boundary elements, check for any loop that the
23589  // shared boundary may be creating
23590 
23591  // The vector of the elements
23592  Vector<FiniteElement*> tmp_vector_sorted_ele_pt;
23593  // Store the list of elements on a vector of elements
23594  for (std::list<FiniteElement*>::iterator it =
23595  tmp_sorted_ele_pt.begin(); it != tmp_sorted_ele_pt.end(); it++)
23596  {
23597  tmp_vector_sorted_ele_pt.push_back((*it));
23598  }
23599 
23600  // The vector of the face elements
23601  Vector<FiniteElement*> tmp_vector_sorted_face_ele_pt;
23602  // Store the list of face elements on a vector of face
23603  // elements
23604  for (std::list<FiniteElement*>::iterator it =
23605  tmp_sorted_face_ele_pt.begin();
23606  it != tmp_sorted_face_ele_pt.end(); it++)
23607  {
23608  tmp_vector_sorted_face_ele_pt.push_back((*it));
23609  }
23610 
23611  // The vector of the face indexes
23612  Vector<int> tmp_vector_sorted_face_index_ele;
23613  // Store the list of elements on a vector of elements
23614  for (std::list<int>::iterator it =
23615  tmp_sorted_face_index_ele.begin();
23616  it != tmp_sorted_face_index_ele.end(); it++)
23617  {
23618  tmp_vector_sorted_face_index_ele.push_back((*it));
23619  }
23620 
23621  // Store the nodes for the new shared polylines without loops
23622  Vector<std::list<Node*> > final_sorted_nodes_pt;
23623  // Store the boundary elements of the shared polyline without
23624  // loops
23625  Vector<Vector<FiniteElement*> > final_boundary_element_pt;
23626  // Store the boundary face elements of the shared polyline
23627  // without loops
23628  Vector<Vector<FiniteElement*> > final_boundary_face_element_pt;
23629  // Face indexes of the boundary elements without loops
23630  Vector<Vector<int> > final_face_index_element;
23631  // Connection flags (to the left) of the shared boundaries
23632  // without loops
23633  Vector<int> final_bound_id_connection_to_the_left;
23634  // Connection flags (to the right) of the shared boundaries
23635  // without loops
23636  Vector<int> final_bound_id_connection_to_the_right;
23637 
23638  // Break any possible loop created by the shared polyline
23639  this->break_loops_on_shared_polyline_load_balance_helper(
23640  local_shd_bnd_id,
23641  tmp_sorted_nodes_pt,
23642  tmp_vector_sorted_ele_pt,
23643  tmp_vector_sorted_face_ele_pt, tmp_vector_sorted_face_index_ele,
23644  bound_id_connection_to_the_left, bound_id_connection_to_the_right,
23645  final_sorted_nodes_pt,
23646  final_boundary_element_pt,
23647  final_boundary_face_element_pt, final_face_index_element,
23648  final_bound_id_connection_to_the_left,
23649  final_bound_id_connection_to_the_right);
23650 
23651  // Get the number of final sorted nodes
23652  const unsigned n_final_sorted_nodes = final_sorted_nodes_pt.size();
23653 
23654  // Loop over the list of final sorted nodes
23655  for (unsigned i = 0; i < n_final_sorted_nodes; i++)
23656  {
23657  // Store the list of nodes that gave rise to the shared
23658  // boundary
23659  local_shd_bnd_id_to_sorted_list_node_pt[local_shd_bnd_id] =
23660  final_sorted_nodes_pt[i];
23661 
23662  // Store the local shared boundary id assigned to the
23663  // elements that will create the shared boundary
23664  proc_local_shared_boundary_id[iproc].push_back(local_shd_bnd_id);
23665 
23666  // Increase the shared boundary id (note that this is only
23667  // used to keep track of the list of nodes that create the
23668  // shared boundaries in the current processor)
23669  local_shd_bnd_id++;
23670 
23671  // Include the vector of elements to the sorted vector
23672  sorted_ele_pt[iproc].push_back(final_boundary_element_pt[i]);
23673 
23674  // Include the vector of face elements to the sorted vector
23675  sorted_face_ele_pt[iproc].
23676  push_back(final_boundary_face_element_pt[i]);
23677 
23678  // Include the vector of elements to the sorted vector
23679  sorted_face_index_ele[iproc].push_back(final_face_index_element[i]);
23680 
23681  // Include the possible associated boundary id to the vector
23682  edge_boundary_id[iproc].push_back(root_edge_bound_id);
23683 
23684  // Include the connection information associated with the
23685  // current set of face elements (that will give rise to a
23686  // shared polyline
23687  // The temporal storage for the boundary connections ids
23688  Vector<int> bnd_connections_ids(2);
23689  bnd_connections_ids[0] = final_bound_id_connection_to_the_left[i];
23690  bnd_connections_ids[1] = final_bound_id_connection_to_the_right[i];
23691  sorted_connection_info[iproc].push_back(bnd_connections_ids);
23692 
23693  } // for (i < n_final_sorted_nodes)
23694 
23695  } // while (nsorted_face_ele < nunsorted_face_ele)
23696 
23697  } // if (iproc != my_rank)
23698 
23699  } // for (iproc < nproc)
23700 
23701  // The time to sort shared boundaries face elements to create a
23702  // continuous representation of the boundary
23703  if (Print_timings_level_load_balance>2)
23704  {
23705  oomph_info << "CPU for joining shared boundary face elements (load balance) [9.5]: "
23706  <<TimingHelpers::timer()-tt_start_join_shd_bnd_face_ele
23707  << std::endl;
23708  }
23709 
23710  // ==================================================================
23711  // END: SORT THE SHARED BOUNDARY FACE ELEMENTS, ADD FACE ELEMENTS TO
23712  // THE LEFT OR RIGHT OF THE ROOT FACE ELEMENT. STOP ADDING WHEN THE
23713  // MOST LEFT OR MOST RIGHT ELEMENT (NODE) IS ALREADY PART OF ANOTHER
23714  // BOUNDARY (THIS MEANS THAT THE SHARED BOUNDARY THAT IS BEING
23715  // CREATED HAS A CONNECTION). ALSO REMEMBER TO CHECK FOR THE CASE
23716  // WHEN THE MOST LEFT OR MOST RIGHT NODE IS A BOUNDARY NODE OF A
23717  // BOUNDARY THAT NO LONGER EXIST IN THE DOMAIN. AT THE END OF THIS
23718  // SECTION WE WILL HAVE THE NUMBER OF SHARED BOUNDARIES OF THIS
23719  // PROCESSOR WITH OTHERS BUT NOT THE GLOBAL SHARED BOUNDARY ID
23720  // ==================================================================
23721 
23722  // ==================================================================
23723  // BEGIN: COMPUTE THE GLOBAL SHARED BOUNDARIES IDS. GATHER THE
23724  // NUMBER OF SHARED BOUNDARIES OF EACH PROCESSOR, THEN A ROOT
23725  // PROCESSOR IS IN CHARGE OF VERIFYING THAT THE SAME NUMBER OF
23726  // SHARED BOUNDARIES HAVE BEEN CREATED BY A PAIR OF PROCESSORS. THE
23727  // ROOT PROCESSOR COMPUTES THE INITIAL GLOBAL SHARED BOUNDARY ID
23728  // BETWEEN EACH PAIR OR PROCESSORS AND SENDS THESE INFO. TO ALL
23729  // PROCESSORS. THE GLOBAL INITIAL AND FINAL SHARED BOUNDARY ID ARE
23730  // ALSO COMPUTED
23731  // ==================================================================
23732 
23733  // Get the time to compute new shared boundaries ids
23734  double tt_start_get_new_shared_boundaries_ids=0.0;
23735  if (Print_timings_level_load_balance>2)
23736  {
23737  tt_start_get_new_shared_boundaries_ids=TimingHelpers::timer();
23738  }
23739 
23740  // Get the number of shared boundaries with in each processor
23741  Vector<unsigned> nshared_boundaries_with_processor(nproc);
23742  // Loop over the processors
23743  for (unsigned iproc = 0; iproc < nproc; iproc++)
23744  {
23745  // No shared boundaries with myself
23746  if (iproc != my_rank)
23747  {
23748  // Store the number of shared boundaries of the current
23749  // processor (my_rank) with the iproc processor
23750  nshared_boundaries_with_processor[iproc] =
23751  sorted_face_ele_pt[iproc].size();
23752 
23753  } // if (iproc != my_rank)
23754 
23755  } // for (iproc < nproc)
23756 
23757  // Each processor sends the number of shared boundaries that it has
23758  // with in each other processor to the "root_processor" which will
23759  // be in charge of checking and computing the global shared
23760  // boundaries ids
23761  const unsigned root_processor = 0;
23762 
23763  // Get the communicator of the mesh
23764  OomphCommunicator* comm_pt = this->communicator_pt();
23765 
23766  // Container where to store the info. received from other processor
23767  // in root. It receives from all processors the number of shared
23768  // boundaries that each one has with any other processor
23769  Vector<unsigned> flat_unsigned_root_received_data(nproc*nproc);
23770 
23771  // Gather the info. in the "root_processor"
23772  MPI_Gather(&nshared_boundaries_with_processor[0], // Info. sent from
23773  // each processor
23774  nproc, // Total number of data to send from each
23775  // processor
23776  MPI_UNSIGNED,
23777  &flat_unsigned_root_received_data[0], // Container where
23778  // to receive the
23779  // info. from all
23780  // the processors
23781  nproc, // Number of data to receive from each processor
23782  MPI_UNSIGNED,
23783  root_processor, // The processor that receives all the
23784  // info.
23785  comm_pt->mpi_comm());
23786 
23787  // Container where root store the info. that will be sent back to
23788  // all processor, because root performs a Broadcast operation then
23789  // the info. is received in the same container
23790  Vector<unsigned> flat_unsigned_root_send_receive_data;
23791 
23792  // Compute the new initial and final shared boundary id (they are
23793  // based on the global number of shared boundaries)
23794  unsigned new_initial_shared_boundary_id = 0;
23795  unsigned new_final_shared_boundary_id = 0;
23796 
23797  // Compute the boundaries ids for the shared boundaries
23798  if (my_rank == root_processor)
23799  {
23800  // Change the representation of the data received from all
23801  // processors to a matrix representation for ease access
23802  Vector<Vector<unsigned> > root_nshared_bound_proc_with_proc(nproc);
23803  // Loop over the processors and get the number of shared
23804  // boundaries of processor iproc with jproc
23805  for (unsigned iproc = 0; iproc < nproc; iproc++)
23806  {
23807  // Resize the vector to store the data
23808  root_nshared_bound_proc_with_proc[iproc].resize(nproc);
23809  // Loop over the processors and get the number of shared
23810  // boundaries of processor iproc with jproc
23811  for (unsigned jproc = 0; jproc < nproc; jproc++)
23812  {
23813  root_nshared_bound_proc_with_proc[iproc][jproc] =
23814  flat_unsigned_root_received_data[(iproc * nproc) + jproc];
23815 
23816  } // for (jproc < nproc)
23817 
23818  } // for (iproc < nproc)
23819 
23820 #ifdef PARANOID
23821  // Check that the same number of boundaries are shared by two
23822  // specific processors
23823  for (unsigned iproc = 0; iproc < nproc; iproc++)
23824  {
23825  for (unsigned jproc = 0; jproc < iproc; jproc++)
23826  {
23827  if (root_nshared_bound_proc_with_proc[iproc][jproc] !=
23828  root_nshared_bound_proc_with_proc[jproc][iproc])
23829  {
23830  std::ostringstream error_stream;
23831  error_stream
23832  << "ROOT PROCESSOR ERROR\n\n"
23833  << "The number of shared boundaries between processor ("
23834  << iproc << ") and (" << jproc << ") is not the same:\n"
23835  << "Shared boundaries of processor (" << iproc
23836  << ") with processor (" << jproc << "): ("
23837  << root_nshared_bound_proc_with_proc[iproc][jproc] << ")\n"
23838  << "Shared boundaries of processor (" << jproc
23839  << ") with processor (" << iproc << "): ("
23840  << root_nshared_bound_proc_with_proc[jproc][iproc] << ")\n\n";
23841  throw OomphLibError(error_stream.str(),
23842  OOMPH_CURRENT_FUNCTION,
23843  OOMPH_EXCEPTION_LOCATION);
23844 
23845  } // The number of shared boundaries between processors
23846  // "iproc" and "jproc" is not the same
23847 
23848  } // for (jproc < iproc)
23849 
23850  } // for (iproc < nproc)
23851 #endif
23852 
23853  // The enumeration of the shared boundaries starts from the lowest
23854  // processor number to the highest processor number
23855 
23856  // Two processors share the same boundaries ids, the lowest
23857  // processor number is the one in charge of computing the shared
23858  // boundaries ids
23859  Vector<Vector<unsigned> > start_shared_bound_id_proc_with_proc(nproc);
23860  // Resize the vector, we can not do it when storing the
23861  // info. because of the strategy to save the info.
23862  for (unsigned iproc = 0; iproc < nproc; iproc++)
23863  {start_shared_bound_id_proc_with_proc[iproc].resize(nproc);}
23864 
23865  // The shared boundaries ids start from the current number of
23866  // original boundaries
23867  unsigned shared_bound_id = this->nboundary();
23868 
23869  // Set the new initial shared boundary id
23870  new_initial_shared_boundary_id = shared_bound_id;
23871 
23872  // Assign the global shared boundary id for the shared boundaries
23873  for (unsigned iproc = 0; iproc < nproc; iproc++)
23874  {
23875  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
23876  {
23877  // Are there shared boundaries between the pair of processors
23878  if (root_nshared_bound_proc_with_proc[iproc][jproc] > 0)
23879  {
23880  // Set the start boundary id of processor "iproc" with
23881  // processor "jproc" and viceversa
23882  start_shared_bound_id_proc_with_proc[iproc][jproc] = shared_bound_id;
23883  start_shared_bound_id_proc_with_proc[jproc][iproc] = shared_bound_id;
23884  // Increase the shared boundary id counter with as many
23885  // shared boundaries there are between the iproc and jproc
23886  // processor
23887  shared_bound_id+= root_nshared_bound_proc_with_proc[iproc][jproc];
23888  } // if (root_nshared_bound_proc_with_proc[iproc][jproc] > 0)
23889 
23890  } // for (jproc < iproc)
23891 
23892  } // for (iproc < nproc)
23893 
23894  // Set the new final shared boundary id
23895  new_final_shared_boundary_id = shared_bound_id;
23896 
23897  // Prepare the info. to send back to each processor
23898  Vector<unsigned> send_start_shared_bound_id_proc_with_proc(nproc*nproc);
23899 
23900  // Copy the info. to the storage to send the info. back to other
23901  // processors
23902  for (unsigned iproc = 0; iproc < nproc; iproc++)
23903  {
23904  for (unsigned jproc = 0; jproc < nproc; jproc++)
23905  {
23906  // Get the initial shared boundary id between each pair of
23907  // processors (iproc, jproc)
23908  const unsigned initial_shd_bnd_id =
23909  start_shared_bound_id_proc_with_proc[iproc][jproc];
23910  flat_unsigned_root_send_receive_data.push_back(initial_shd_bnd_id);
23911 
23912  // .. then copy the number of shared boundaries that there are
23913  // between processor iproc and jproc
23914  const unsigned nshared_bnd_iproc_jproc =
23915  root_nshared_bound_proc_with_proc[iproc][jproc];
23916  flat_unsigned_root_send_receive_data.push_back(nshared_bnd_iproc_jproc);
23917 
23918  } // for (jproc < nproc)
23919 
23920  } // for (iproc < nproc)
23921 
23922  // .. at the end of the data to send include the global initial
23923  // shared boundary id
23924  flat_unsigned_root_send_receive_data.
23925  push_back(new_initial_shared_boundary_id);
23926 
23927  // ... and the global final shared boundary id
23928  flat_unsigned_root_send_receive_data.
23929  push_back(new_final_shared_boundary_id);
23930 
23931  } // if (my_rank == root_processor)
23932 
23933  // Send the initial shared boundaries ids and the number of shared
23934  // boundaries between all procesors to all processors. All
23935  // processors need to know this info.
23936 
23937  // The number of data that will be sent by root to other processors
23938  // and the number of data that other processors receive from root,
23939  // it is the same because it is performed via a Broadcast
23940  unsigned root_ndata_sent_to_all_proc =
23941  flat_unsigned_root_send_receive_data.size();
23942 
23943  MPI_Bcast(&root_ndata_sent_to_all_proc, // Data to send
23944  1, MPI_UNSIGNED, root_processor,
23945  comm_pt->mpi_comm());
23946 
23947  // Resize the container if this is a processor that receives data
23948  if (my_rank != root_processor)
23949  {
23950  flat_unsigned_root_send_receive_data.resize(root_ndata_sent_to_all_proc);
23951  }
23952 
23953  // Send back the start boundaries ids for the shared boundaries
23954  // Scatter the info. from the "root_processor"
23955  MPI_Bcast(&flat_unsigned_root_send_receive_data[0], // Info. sent to
23956  // each
23957  // processor
23958  root_ndata_sent_to_all_proc, // Total number of data to
23959  // send to each processor
23960  MPI_UNSIGNED,
23961  root_processor, // The processor that sends all the info.
23962  comm_pt->mpi_comm());
23963 
23964  // The container to store the initial shared boundaries ids between
23965  // each pair of processors
23966  Vector<Vector<unsigned> > initial_shared_bound_id_proc_with_proc(nproc);
23967 
23968  // All processors need to know how many shared boundaries there are
23969  // between each pair of processors
23970 
23971  // The number of shared boundaries between each pair of processors
23972  Vector<Vector<unsigned> > nshared_bound_proc_with_proc(nproc);
23973 
23974  unsigned iflat_counter = 0;
23975  // Fill the containers with the received info. from root processor
23976  for (unsigned iproc = 0; iproc < nproc; iproc++)
23977  {
23978  // Resize the containers
23979  initial_shared_bound_id_proc_with_proc[iproc].resize(nproc);
23980  nshared_bound_proc_with_proc[iproc].resize(nproc);
23981 
23982  // Loop over the processors
23983  for (unsigned jproc = 0; jproc < nproc; jproc++)
23984  {
23985  // Get the initial shared boundary id between each pair of
23986  // processors (iproc, jproc)
23987  initial_shared_bound_id_proc_with_proc[iproc][jproc] =
23988  flat_unsigned_root_send_receive_data[iflat_counter++];
23989 
23990  // .. and copy the number of shared boundaries that there are
23991  // between processor iproc and jproc
23992  nshared_bound_proc_with_proc[iproc][jproc] =
23993  flat_unsigned_root_send_receive_data[iflat_counter++];
23994 
23995  } // for (jproc < nproc)
23996 
23997  } // for (iproc < nproc)
23998 
23999  // Read the new initial shared boundary id
24000  new_initial_shared_boundary_id =
24001  flat_unsigned_root_send_receive_data[root_ndata_sent_to_all_proc-2];
24002 
24003  // Read the new final shared boundary id
24004  new_final_shared_boundary_id =
24005  flat_unsigned_root_send_receive_data[root_ndata_sent_to_all_proc-1];
24006 
24007  // The time to compute new shared boundaries ids
24008  if (Print_timings_level_load_balance>2)
24009  {
24010  oomph_info << "CPU for computing new shared boundaries ids (load balance) [9.6]: "
24011  <<TimingHelpers::timer()-tt_start_get_new_shared_boundaries_ids
24012  << std::endl;
24013  }
24014 
24015  // ==================================================================
24016  // END: COMPUTE THE GLOBAL SHARED BOUNDARIES IDS. GATHER THE NUMBER
24017  // OF SHARED BOUNDARIES OF EACH PROCESSOR, THEN A ROOT PROCESSOR IS
24018  // IN CHARGE OF VERIFYING THAT THE SAME NUMBER OF SHARED BOUNDARIES
24019  // HAVE BEEN CREATED BY A PAIR OF PROCESSORS. THE ROOT PROCESSOR
24020  // COMPUTES THE INITIAL GLOBAL SHARED BOUNDARY ID BETWEEN EACH PAIR
24021  // OR PROCESSORS AND SENDS THESE INFO. TO ALL PROCESSORS. THE GLOBAL
24022  // INITIAL AND FINAL SHARED BOUNDARY ID ARE ALSO COMPUTED
24023  // ==================================================================
24024 
24025  // ==================================================================
24026  // BEGIN: CREATE THE NEW SHARED BOUNDARIES. DELETE THE OLD SHARED
24027  // BOUNDARIES INFORMATION. FILL THE DATA STRUCTURES WITH THE NEW
24028  // SHARED BOUNDARIES INFO.
24029  // ==================================================================
24030 
24031  // Get the time to create new shared boundaries representations
24032  double tt_start_create_new_shared_boundaries_polylines=0.0;
24033  if (Print_timings_level_load_balance>2)
24034  {
24035  tt_start_create_new_shared_boundaries_polylines=TimingHelpers::timer();
24036  }
24037 
24038  // Create the shared boundaries and establish all the related info.
24039  // - Create Polylines
24040  // - Store shared boundary elements
24041  // - Fill data structures to know which shared boundaries belong to
24042  // which processor
24043 
24044  // Resize the shared polylines container
24045  this->flush_shared_boundary_polyline_pt();
24046  this->Shared_boundary_polyline_pt.resize(nproc);
24047 
24048  // Resize for the boundaries ids shared with all processors
24049  this->Shared_boundaries_ids.clear();
24050  this->Shared_boundaries_ids.resize(nproc);
24051  for (unsigned iproc = 0; iproc < nproc; iproc++)
24052  {
24053  this->Shared_boundaries_ids[iproc].clear();
24054  this->Shared_boundaries_ids[iproc].resize(nproc);
24055  } // for (iproc < nproc)
24056 
24057  // Clear data
24058  this->Shared_boundary_from_processors.clear();
24059  this->Shared_boundary_overlaps_internal_boundary.clear();
24060  this->Boundary_was_splitted.clear();
24061  this->Boundary_subpolylines.clear();
24062  this->Boundary_marked_as_shared_boundary.clear();
24063 
24064  // Flush data
24065  this->flush_shared_boundary_element();
24066  this->flush_face_index_at_shared_boundary();
24067  this->flush_shared_boundary_node();
24068  this->flush_sorted_shared_boundary_node();
24069 
24070  // Store the old local inital shared boundary id (used to map from
24071  // local shared boundary id to global shared boundary id)
24072  const unsigned old_local_shd_bnd_id = this->Initial_shared_boundary_id;
24073 
24074  // Update the initial and final shared boundary id
24075  this->Initial_shared_boundary_id = new_initial_shared_boundary_id;
24076  this->Final_shared_boundary_id = new_final_shared_boundary_id;
24077 
24078  // Storage for the new created polylines between the current
24079  // processor (my_rank) and the other processors, unsorted polylines
24080  Vector<TriangleMeshPolyLine *> unsorted_polylines_pt;
24081 
24082  // Map to get the global shared boundary id from the local shared
24083  // boundary id. Note that this is only used to get the global shared
24084  // boundary id when the shared boundary that is being created has
24085  // connections
24086  std::map<unsigned, unsigned> local_to_global_shd_bnd_id;
24087 
24088  // Each processor knows the boundaries ids for each of the shared
24089  // boundaries it has, establish that info. in the proper containers
24090  // Additionally, store the shared boundaries of ALL processors with
24091  // ALL processors, but only create the shared boundaries (and their
24092  // respective polylines) of the current processor (my_rank)
24093  for (unsigned iproc = 0; iproc < nproc; iproc++)
24094  {
24095  // Avoid creating double shared boundaries, the shared boundaries
24096  // created between processor "iproc" and processor "jproc" are the
24097  // same than those created between processor "jproc" and processor
24098  // "iproc"
24099  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
24100  {
24101  // If we are working with the current processor (my_rank) then
24102  // create the shared boundaries, if that is not the case then
24103  // only fill the info. on the proper containers
24104  if (iproc == my_rank || jproc == my_rank)
24105  {
24106  // Check the condition that made it get here
24107  unsigned ref_proc = 0;
24108  if (iproc == my_rank)
24109  {ref_proc = jproc;}
24110  else if (jproc == my_rank)
24111  {ref_proc = iproc;}
24112 
24113  // Get the number of shared boundaries between processor iproc
24114  // and processor jproc
24115  const unsigned nshared_bound_iproc_jproc =
24116  nshared_bound_proc_with_proc[iproc][jproc];
24117 
24118  // Loop over the number of shared boundaries
24119  for (unsigned counter = 0;
24120  counter < nshared_bound_iproc_jproc;
24121  counter++)
24122  {
24123  // Compute the shared boundary id for the shared boundary
24124  const unsigned shd_bnd_id =
24125  initial_shared_bound_id_proc_with_proc[iproc][jproc] + counter;
24126  // Set up the shared boundaries between "iproc" (my_rank)
24127  // and "jproc"
24128  this->Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
24129  this->Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
24130 
24131  // Specify the processors involved for the creation of the
24132  // shared boundary
24133  Vector<unsigned> processors(2);
24134  processors[0] = iproc;
24135  processors[1] = jproc;
24136  this->Shared_boundary_from_processors[shd_bnd_id] = processors;
24137 
24138  // Get the possible root edge id associated to the shared
24139  // boundary (useful when the shared boundary overlaps an
24140  // original boundary)
24141  int root_edge_bound_id = edge_boundary_id[ref_proc][counter];
24142  // Check if the shared boundary is overlapping (or is part)
24143  // of an internal boundary
24144  if (root_edge_bound_id != -1)
24145  {
24146  // If the shared boundary is part of an internal boundary then
24147  // mark the shared boundary
24148  this->Shared_boundary_overlaps_internal_boundary[shd_bnd_id] =
24149  static_cast<unsigned>(root_edge_bound_id);
24150  } // if (root_edge_bound_id != -1)
24151 
24152  // Storing for the nodes of the polyline (these are different
24153  // from the nodes on the face elements -- it is actually a
24154  // sub-set -- since the polyline is created from the first and
24155  // last nodes on the face elements)
24156  Vector<Node*> node_pt_to_create_shared_polyline;
24157 
24158  // Add the first node for the very first face element. In
24159  // the loop we will only add the last node of the face
24160  // element
24161  FiniteElement* first_face_ele_pt =
24162  sorted_face_ele_pt[ref_proc][counter][0];
24163 
24164  // Get the number of nodes on the first face element
24165  const unsigned first_face_ele_nnodes = first_face_ele_pt->nnode();
24166  if (!is_inverted[first_face_ele_pt])
24167  {
24168  // Get the first node
24169  Node* first_node_pt = first_face_ele_pt->node_pt(0);
24170  // Add the node to create the polyline
24171  node_pt_to_create_shared_polyline.push_back(first_node_pt);
24172  // Add the first node to the shared boundary
24173  this->add_shared_boundary_node(shd_bnd_id, first_node_pt);
24174  }
24175  else
24176  {
24177  // Get the first node in the inverted face element
24178  Node* first_node_pt =
24179  first_face_ele_pt->node_pt(first_face_ele_nnodes - 1);
24180  // Add the node to create the polyline
24181  node_pt_to_create_shared_polyline.push_back(first_node_pt);
24182  // Add the first node to the shared boundary
24183  this->add_shared_boundary_node(shd_bnd_id, first_node_pt);
24184  }
24185 
24186  // ... and extract only the last nodes of the face elements
24187  // in the next loop and add them in the vector of nodes to
24188  // create polylines (node_pt_to_create_shared_polyline)
24189 
24190  // Get the number of elements
24191  const unsigned nshared_boundary_elements =
24192  sorted_face_ele_pt[ref_proc][counter].size();
24193 
24194  // Store the shared boundary elements, nodes and get the
24195  // sorted nodes to create the polyline
24196  for (unsigned ie = 0 ; ie < nshared_boundary_elements; ie++)
24197  {
24198  // Get the bulk element version of the face element
24199  FiniteElement* bulk_ele_pt = sorted_ele_pt[ref_proc][counter][ie];
24200 
24201  // Add the shared boundary element and associate it to the
24202  // "shd_bnd_id"
24203  this->add_shared_boundary_element(shd_bnd_id,
24204  bulk_ele_pt);
24205 
24206  // Get the face index from which the face element was
24207  // created from the bulk element
24208  const int face_index =
24209  sorted_face_index_ele[ref_proc][counter][ie];
24210 
24211  // Add the face index to the face indexes of the shared
24212  // boundary
24213  this->add_face_index_at_shared_boundary(shd_bnd_id,
24214  face_index);
24215 
24216  // Get the face element to obtain the last node
24217  FiniteElement* face_ele_pt =
24218  sorted_face_ele_pt[ref_proc][counter][ie];
24219 
24220  // Get the number of nodes
24221  const unsigned nnodes = face_ele_pt->nnode();
24222  if (!is_inverted[face_ele_pt])
24223  {
24224  // We have already added the first node, then start from
24225  // the second one
24226  for (unsigned n = 1; n < nnodes; n++)
24227  {
24228  // Get the node to be added
24229  Node* node_pt = face_ele_pt->node_pt(n);
24230  // Add the node and associate it to the shared boundary
24231  this->add_shared_boundary_node(shd_bnd_id, node_pt);
24232  } // for (n < nnodes)
24233 
24234  // Add the last node of the face element to the vector of
24235  // nodes to create the polyline
24236  // Get the last node
24237  Node* last_node_pt = face_ele_pt->node_pt(nnodes - 1);
24238  node_pt_to_create_shared_polyline.push_back(last_node_pt);
24239  } // if (!is_inverted[face_ele_pt])
24240  else
24241  {
24242  // We have already added the first node, then start from
24243  // the second one (in reverse order)
24244  for (int n = nnodes-2; n >= 0; n--)
24245  {
24246  // Get the node to be added
24247  Node* node_pt = face_ele_pt->node_pt(n);
24248  // Add the node and associate it to the shared boundary
24249  this->add_shared_boundary_node(shd_bnd_id, node_pt);
24250  } // for (n < nnodes)
24251 
24252  // Add the last node of the face element to the vector of
24253  // nodes to create the polyline
24254  // Get the last node
24255  Node* last_node_pt = face_ele_pt->node_pt(0);
24256  node_pt_to_create_shared_polyline.push_back(last_node_pt);
24257 
24258  } // else if (!is_inverted[face_ele_pt])
24259 
24260  } // for (ie < nshared_boundary_elements)
24261 
24262  // The number of nodes for the shared boundary polyline
24263  const unsigned nnodes_to_create_shared_boundary =
24264  node_pt_to_create_shared_polyline.size();
24265 
24266  // Get the vertices that create the shared boundary polyline
24267  Vector<Vector<double> > vertices(nnodes_to_create_shared_boundary);
24268  for (unsigned n = 0; n < nnodes_to_create_shared_boundary; n++)
24269  {
24270  vertices[n].resize(2);
24271  // Get the node
24272  Node* tmp_node_pt = node_pt_to_create_shared_polyline[n];
24273  // Get the vertices
24274  vertices[n][0] = tmp_node_pt->x(0);
24275  vertices[n][1] = tmp_node_pt->x(1);
24276  } // for (n < nnodes_to_create_shared_boundary)
24277 
24278  // Create the polyline
24279  TriangleMeshPolyLine *polyline_pt =
24280  new TriangleMeshPolyLine(vertices, shd_bnd_id);
24281 
24282  // Updates bnd_id<--->curve section map
24283  this->Boundary_curve_section_pt[shd_bnd_id] = polyline_pt;
24284 
24285  // Add the new created polyline to the list of unsorted
24286  // polylines
24287  unsorted_polylines_pt.push_back(polyline_pt);
24288 
24289  // Mark the polyline for deletion (when calling destructor)
24290  this->Free_curve_section_pt.insert(polyline_pt);
24291 
24292  // Now assign the connection information
24293  // ---------------------------------------------------------
24294  // Get the local shared boundary id associated to the
24295  // elements that gave rise to this shared boundary
24296  const unsigned local_shd_bnd_id =
24297  proc_local_shared_boundary_id[ref_proc][counter];
24298 
24299  // Associate the local shared boundary to the global shared
24300  // boundary
24301  local_to_global_shd_bnd_id[local_shd_bnd_id] = shd_bnd_id;
24302 
24303  // Get the correct shared boundaries ids, from the local
24304  // shared boundaries ids established at the identification
24305  // of the conections
24306 
24307  // Get the local bnd id for the connection to the left
24308  int tmp_bnd_id_connection_to_the_left =
24309  sorted_connection_info[ref_proc][counter][0];
24310  // Get the local bnd id for the connection to the right
24311  int tmp_bnd_id_connection_to_the_right =
24312  sorted_connection_info[ref_proc][counter][1];
24313 
24314  // The global shared boundaries ids for connections to the
24315  // left or right
24316  int bnd_id_connection_to_the_left = -1;
24317  int bnd_id_connection_to_the_right = -1;
24318 
24319  // To the left
24320  // --------------
24321 
24322  // If the connection is with the same shared boundary then
24323  // set the current boundary id
24324  if (tmp_bnd_id_connection_to_the_left == -2)
24325  {
24326  // Set the current shared boundary id
24327  bnd_id_connection_to_the_left = shd_bnd_id;
24328  } // if (tmp_bnd_id_connection_to_the_left == -2)
24329 
24330  // Check if the connection was a stop adding nodes condition
24331  if (tmp_bnd_id_connection_to_the_left == -3)
24332  {
24333  // Set as no connected
24334  bnd_id_connection_to_the_left = -1;
24335  } // if (tmp_bnd_id_connection_to_the_left == -3)
24336 
24337  // There is a connection with another boundary, check if it
24338  // is a shared boundary or an original boundary
24339  if (tmp_bnd_id_connection_to_the_left >=
24340  static_cast<int>(old_local_shd_bnd_id))
24341  {
24342  // The connection is with a shared boundary, get the
24343  // global shared boundary id and set the connection
24344 #ifdef PARANOID
24345  std::map<unsigned, unsigned>::iterator it =
24346  local_to_global_shd_bnd_id.find(
24347  static_cast<unsigned>(tmp_bnd_id_connection_to_the_left));
24348  // If the global shared boundary id was not found we
24349  // are in trouble
24350  if (it==local_to_global_shd_bnd_id.end())
24351  {
24352  std::stringstream error_message;
24353  error_message
24354  << "The global shared boundary id was not found for\n"
24355  << "the local shared boundary shared with processor ("
24356  << ref_proc <<").\n"
24357  << "This processor: (" << my_rank << ")\n"
24358  << "Boundary shared with processor: (" << ref_proc << ")\n"
24359  << "Local shared boundary: ("
24360  << tmp_bnd_id_connection_to_the_left << ")\n";
24361  throw OomphLibError(error_message.str(),
24362  OOMPH_CURRENT_FUNCTION,
24363  OOMPH_EXCEPTION_LOCATION);
24364  } // if (it==local_to_global_shd_bnd_id.end())
24365 #endif
24366 
24367  // Get the global shared boundary id
24368  bnd_id_connection_to_the_left =
24369  local_to_global_shd_bnd_id[
24370  static_cast<unsigned>(tmp_bnd_id_connection_to_the_left)];
24371 
24372  }
24373  else
24374  {
24375  // The connection is with an original boundary, copy
24376  // the boundary id
24377  bnd_id_connection_to_the_left =
24378  tmp_bnd_id_connection_to_the_left;
24379 
24380  } // else (connection with a shared boundary)
24381 
24382  // To the right
24383  // --------------
24384 
24385  // If the connection is with the same shared boundary then
24386  // set the current boundary id
24387  if (tmp_bnd_id_connection_to_the_right == -2)
24388  {
24389  // Set the current shared boundary id
24390  bnd_id_connection_to_the_right = shd_bnd_id;
24391  } // if (tmp_bnd_id_connection_to_the_right == -2)
24392 
24393  // Check if the connection was a stop adding nodes condition
24394  if (tmp_bnd_id_connection_to_the_right == -3)
24395  {
24396  // Set as no connected
24397  bnd_id_connection_to_the_right = -1;
24398  } // if (tmp_bnd_id_connection_to_the_right == -3)
24399 
24400  // There is a connection with another boundary, check if it
24401  // is a shared boundary or an original boundary
24402  if (tmp_bnd_id_connection_to_the_right >=
24403  static_cast<int>(old_local_shd_bnd_id))
24404  {
24405  // The connection is with a shared boundary, get the
24406  // global shared boundary id and set the connection
24407 #ifdef PARANOID
24408  std::map<unsigned, unsigned>::iterator it =
24409  local_to_global_shd_bnd_id.find(
24410  static_cast<unsigned>(tmp_bnd_id_connection_to_the_right));
24411  // If the global shared boundary id was not found we
24412  // are in trouble
24413  if (it==local_to_global_shd_bnd_id.end())
24414  {
24415  std::stringstream error_message;
24416  error_message
24417  << "The global shared boundary id was not found for\n"
24418  << "the local shared boundary shared with processor ("
24419  << ref_proc <<").\n"
24420  << "This processor: (" << my_rank << ")\n"
24421  << "Boundary shared with processor: (" << ref_proc << ")\n"
24422  << "Local shared boundary: ("
24423  << tmp_bnd_id_connection_to_the_right << ")\n";
24424  throw OomphLibError(error_message.str(),
24425  OOMPH_CURRENT_FUNCTION,
24426  OOMPH_EXCEPTION_LOCATION);
24427  } // if (it==local_to_global_shd_bnd_id.end())
24428 #endif
24429  // Get the global shared boundary id
24430  bnd_id_connection_to_the_right =
24431  local_to_global_shd_bnd_id[
24432  static_cast<unsigned>(tmp_bnd_id_connection_to_the_right)];
24433 
24434  }
24435  else
24436  {
24437  // The connection is with an original boundary, copy the
24438  // boundary id
24439  bnd_id_connection_to_the_right =
24440  tmp_bnd_id_connection_to_the_right;
24441 
24442  } // else (connection with a shared boundary)
24443 
24444  // --------------------------------
24445  // Set the connection to the left
24446  if (bnd_id_connection_to_the_left != -1)
24447  {
24448  // Get the unsigned version of the boundary id to the left
24449  const unsigned ubnd_id_connection_to_the_left =
24450  static_cast<unsigned>(bnd_id_connection_to_the_left);
24451  // Set the initial vertex as connected
24452  polyline_pt->set_initial_vertex_connected();
24453  // Set the initial vertex connected boundary id
24454  polyline_pt->initial_vertex_connected_bnd_id() =
24455  ubnd_id_connection_to_the_left;
24456  // Set the chunk number to zero
24457  polyline_pt->initial_vertex_connected_n_chunk() = 0;
24458 
24459  } // if (bnd_id_connection_to_the_left != -1)
24460 
24461  // ---------------------------------
24462  // Set the connection to the right
24463  if (bnd_id_connection_to_the_right != -1)
24464  {
24465  // Get the unsigned version of the boundary id to the
24466  // right
24467  const unsigned ubnd_id_connection_to_the_right =
24468  static_cast<unsigned>(bnd_id_connection_to_the_right);
24469  // Set the final vertex as connected
24470  polyline_pt->set_final_vertex_connected();
24471  // Set the final vertex connected boundary id
24472  polyline_pt->final_vertex_connected_bnd_id() =
24473  ubnd_id_connection_to_the_right;
24474  // Set the chunk number to zero
24475  polyline_pt->final_vertex_connected_n_chunk() = 0;
24476 
24477  } // if (bnd_id_connection_to_the_right != -1)
24478 
24479  } // for (counter < nshared_bound_iproc_jproc)
24480 
24481  } // if (iproc == my_rank || jproc == my_rank)
24482  else
24483  {
24484  // We are not working with the current processor, then we only
24485  // need to fill the containers
24486 
24487  // Get the number of shared boundaries between processor iproc
24488  // and processor jproc
24489  const unsigned nshared_bound_iproc_jproc =
24490  nshared_bound_proc_with_proc[iproc][jproc];
24491  // Loop over the number of shared boundaries
24492  for (unsigned counter = 0;
24493  counter < nshared_bound_iproc_jproc;
24494  counter++)
24495  {
24496  // Compute the shared boundary id for the shared boundary
24497  const unsigned shd_bnd_id =
24498  initial_shared_bound_id_proc_with_proc[iproc][jproc] + counter;
24499 
24500  // Set up the shared boundaries between "iproc" and "jproc"
24501  this->Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
24502  this->Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
24503 
24504  // Specify the processors involved for the creation of the
24505  // shared boundary
24506  Vector<unsigned> processors(2);
24507  processors[0] = iproc;
24508  processors[1] = jproc;
24509  this->Shared_boundary_from_processors[shd_bnd_id] = processors;
24510 
24511  } // for (counter < nshared_bound_iproc_jproc)
24512 
24513  } // else if (iproc == my_rank || jproc == my_rank)
24514 
24515  } // for (jproc < nproc)
24516 
24517  } // for (iproc < nproc)
24518 
24519  // Get the time to create new shared boundaries representations
24520  if (Print_timings_level_load_balance>2)
24521  {
24522  oomph_info << "CPU for creating new shared boundaries representations (load balance) [9.7]: "
24523  <<TimingHelpers::timer()-tt_start_create_new_shared_boundaries_polylines
24524  << std::endl;
24525  }
24526 
24527  // ==================================================================
24528  // END: CREATE THE NEW SHARED BOUNDARIES. DELETE THE OLD SHARED
24529  // BOUNDARIES INFORMATION. FILL THE DATA STRUCTURES WITH THE NEW
24530  // SHARED BOUNDARIES INFO.
24531  // ==================================================================
24532 
24533  // ==================================================================
24534  // BEGIN: SORT THE SHARED BOUNDARIES AND CREATE SHARED CURVES (A SET
24535  // OF CONTIGUOUS SHARED POLYLINES). STORE THEM IN THE GLOBAL
24536  // CONTAINER FOR SHARED BOUNDARIES. FREE MEMORY BY DELETING FACE
24537  // ELEMENTS
24538  // ==================================================================
24539 
24540  // Get the time to create the new shared curves
24541  double tt_start_create_new_shared_curves=0.0;
24542  if (Print_timings_level_load_balance>2)
24543  {
24544  tt_start_create_new_shared_curves=TimingHelpers::timer();
24545  }
24546 
24547  // Sort the polylines and find if they create a contiguous open
24548  // curve
24549  if (unsorted_polylines_pt.size() > 0)
24550  {
24551  // Now that we have all the new unsorted polylines on "my_rank"x
24552  // processor it is time to sort them so they be all contiguous
24553  this->sort_polylines_helper(unsorted_polylines_pt,
24554  this->Shared_boundary_polyline_pt[my_rank]);
24555  }
24556 
24557  // Free the memory allocated for the face elements
24558  for (unsigned iproc = 0; iproc < nproc; iproc++)
24559  {
24560  const unsigned nface_ele = unsorted_face_ele_pt[iproc].size();
24561  for (unsigned e = 0; e < nface_ele; e++)
24562  {
24563  delete unsorted_face_ele_pt[iproc][e];
24564  unsorted_face_ele_pt[iproc][e] = 0;
24565  } // for (e < nface_ele)
24566 
24567  } // for (iproc < nproc)
24568 
24569  // The time to create the new shared curves
24570  if (Print_timings_level_load_balance>2)
24571  {
24572  oomph_info << "CPU for creating the new shared curves (load balance) [9.8]: "
24573  <<TimingHelpers::timer()-tt_start_create_new_shared_curves
24574  << std::endl;
24575  }
24576 
24577  // ==================================================================
24578  // END: SORT THE SHARED BOUNDARIES AND CREATE SHARED CURVES (A SET
24579  // OF CONTIGUOUS SHARED POLYLINES). STORE THEM IN THE GLOBAL
24580  // CONTAINER FOR SHARED BOUNDARIES. FREE MEMORY BY DELETING FACE
24581  // ELEMENTS
24582  // ==================================================================
24583 
24584  }
24585 
24586  //======================================================================
24587  // Computes the degree of the nodes on the shared boundaries, the
24588  // degree of the node is computed from the global graph created by the
24589  // shared boundaries of all processors
24590  //======================================================================
24591  template <class ELEMENT>
24594  &unsorted_face_ele_pt,
24595  std::map<Node*, unsigned>
24596  &global_node_degree)
24597  {
24598  // Get the rank and number of processors
24599  const unsigned nproc = this->communicator_pt()->nproc();
24600  const unsigned my_rank = this->communicator_pt()->my_rank();
24601 
24602  // Store a temporary sorting of the nodes, starting from the
24603  // lower-left position
24604  Vector<Vector<Node*> > tmp_sorted_shared_node_pt(nproc);
24605 
24606  // Store the alias of the node, it may be shared by more than two
24607  // processors, they should know that the node is the same
24608  // [0] iproc, processor with which the current processor shared the node
24609  // [1] node #, number of node in the number of nodes shared with iproc
24610  // processor
24611  std::map<Node*, Vector<Vector<unsigned> > > node_alias;
24612 
24613  // Stores the local adjacency matrix
24614  // (nproc*n_shared_nodes*n_shared_nodes)
24615  Vector<Vector<Vector<unsigned> > > local_adjacency_matrix(nproc);
24616 
24617  // Sort the nodes and create the adjacency matrix of each sub-graph
24618  // created by the shared edges
24619  create_adjacency_matrix_new_shared_edges_helper(unsorted_face_ele_pt,
24620  tmp_sorted_shared_node_pt,
24621  node_alias,
24622  local_adjacency_matrix);
24623 
24624  // Prepare the info. to be sent to the root processor, which will be
24625  // in charge of updating the nodes degree by combining the info. of
24626  // all the processors
24627 
24628  // The flat package with the info. to send to root
24629  Vector<unsigned> package_unsigned_send_data_to_root;
24630 
24631  // Encode the info. that will be sent to the root processor
24632 
24633  // Loop over the temporary sorted nodes between each pair of
24634  // processors
24635  for (unsigned iproc = 0; iproc < nproc; iproc++)
24636  {
24637  // Send the processor index
24638  package_unsigned_send_data_to_root.push_back(iproc);
24639 
24640  // Get the number of nodes shared between the processors
24641  const unsigned n_nodes = tmp_sorted_shared_node_pt[iproc].size();
24642 
24643  // Send the number of nodes shared with the iproc processor
24644  package_unsigned_send_data_to_root.push_back(n_nodes);
24645 
24646  // Loop over the nodes
24647  for (unsigned ishd = 0; ishd < n_nodes; ishd++)
24648  {
24649  // Get the node
24650  Node* shd_node_pt = tmp_sorted_shared_node_pt[iproc][ishd];
24651 
24652  // Get the alias info.
24653  Vector<Vector<unsigned> > alias_node_info = node_alias[shd_node_pt];
24654 
24655  // Get the number of alias for the node
24656  const unsigned n_alias = alias_node_info.size();
24657 
24658  // Send the number of alias assigned to the node
24659  package_unsigned_send_data_to_root.push_back(n_alias);
24660 
24661  // Loop over the alias to include them in the package
24662  for (unsigned i = 0; i < n_alias; i++)
24663  {
24664  // Send the alias info.
24665  // The current processor
24666  package_unsigned_send_data_to_root.push_back(alias_node_info[i][0]);
24667  // The prociesso with which is shared
24668  package_unsigned_send_data_to_root.push_back(alias_node_info[i][1]);
24669  // The index of the node
24670  package_unsigned_send_data_to_root.push_back(alias_node_info[i][2]);
24671  } // for (i < n_alias)
24672 
24673  } // for (ishd < n_nodes)
24674 
24675  // Now send the adjacency matrix
24676  for (unsigned i = 0; i < n_nodes; i++)
24677  {
24678  for (unsigned j = 0; j < n_nodes; j++)
24679  {
24680  // Package the adjacency matrix
24681  package_unsigned_send_data_to_root.
24682  push_back(local_adjacency_matrix[iproc][i][j]);
24683 
24684  } // for (j < n_nodes)
24685 
24686  } // for (i < n_nodes)
24687 
24688  } // for (iproc < nproc)
24689 
24690  // Define the root processor
24691  const unsigned root_processor = 0;
24692 
24693  // Get the communicator of the mesh
24694  OomphCommunicator* comm_pt = this->communicator_pt();
24695 
24696  // Number of data send. from this processor to root processor
24697  unsigned n_unsigned_data_send_to_root =
24698  package_unsigned_send_data_to_root.size();
24699 
24700  // Store the number of data to receive from each processor in root
24701  Vector<int> n_unsigned_data_received_in_root(nproc, 0);
24702 
24703  // Send the number of data that each processor will send to root
24704  // Gather the info. in the "root_processor"
24705  MPI_Gather(&n_unsigned_data_send_to_root, // Info. sent from
24706  // each processor
24707  1, // Total number of data to send from each processor
24708  MPI_UNSIGNED,
24709  &n_unsigned_data_received_in_root[0], // Container where
24710  // to receive the
24711  // info. from all
24712  // the processors
24713  1, // Number of data to receive from each processor
24714  MPI_UNSIGNED,
24715  root_processor, // The processor that receives all the
24716  // info.
24717  comm_pt->mpi_comm());
24718 
24719  // Compute the total number of data to receive from all processors
24720  unsigned n_unsigned_total_data_receive_in_root = 0;
24721  for (unsigned iproc = 0; iproc < nproc; iproc++)
24722  {
24723  // Add the number of data to receive from each processor
24724  n_unsigned_total_data_receive_in_root+=
24725  n_unsigned_data_received_in_root[iproc];
24726  }
24727 
24728  // Compute the offsets from each processor
24729  Vector<int> root_unsigned_offsets_receive(nproc,0);
24730  root_unsigned_offsets_receive[0] = 0;
24731  for (unsigned iproc = 1; iproc < nproc; iproc++)
24732  {
24733  // Compute the offset to store the values received from each
24734  // processor
24735  root_unsigned_offsets_receive[iproc] =
24736  root_unsigned_offsets_receive[iproc-1] +
24737  n_unsigned_data_received_in_root[iproc-1];
24738  }
24739 
24740  // Create at least one entry so we don't get a seg fault below
24741  if (package_unsigned_send_data_to_root.size()==0)
24742  {
24743  package_unsigned_send_data_to_root.resize(1);
24744  }
24745 
24746  // Vector where to receive the data sent from each processor
24748  package_unsigned_data_received_root(n_unsigned_total_data_receive_in_root);
24749  if (my_rank!=root_processor)
24750  {
24751  // Create at least one entry so we don't get a seg fault below
24752  if (package_unsigned_data_received_root.size()==0)
24753  {
24754  package_unsigned_data_received_root.resize(1);
24755  }
24756  } // if (my_rank!=root_processor)
24757 
24758  // Gather the info. from all processors
24759  MPI_Gatherv(&package_unsigned_send_data_to_root[0], // Flat package
24760  // to send
24761  // info. from
24762  // each
24763  // processor
24764  n_unsigned_data_send_to_root, // Total number of data to
24765  // send from each
24766  // processor
24767  MPI_UNSIGNED,
24768  &package_unsigned_data_received_root[0], // Container
24769  // where to
24770  // receive the
24771  // info. from
24772  // all the
24773  // processors
24774  &n_unsigned_data_received_in_root[0], // Number of data
24775  // to receive from
24776  // each processor
24777  &root_unsigned_offsets_receive[0], // The offset to
24778  // store the
24779  // info. from each
24780  // processor
24781  MPI_UNSIGNED,
24782  root_processor, //The processor that receives all the
24783  //info.
24784  comm_pt->mpi_comm());
24785 
24786  // Store the info. to be sent by root to other processors
24787  Vector<unsigned> package_unsigned_data_sent_from_root;
24788  // Total data sent to each processor from root
24789  Vector<int> n_unsigned_data_sent_from_root(nproc, 0);
24790 
24791  // The root processor now has all the info. regarding the shared
24792  // nodes and the adjacency matrix of each pair of processors
24793  if (my_rank == root_processor)
24794  {
24795  // Decode the info. received from all processors
24796  // Counter to decode the info.
24797  unsigned decode_counter = 0;
24798 
24799  // Store the local alias of the nodes in each processor
24800  // [x][][][][] iproc
24801  // [][x][][][] jproc
24802  // [][][x][][] inode
24803  // [][][][x][] ialias
24804  // [][][][][x] alias_data
24806  local_node_alias(nproc);
24807  // Store the local adjacency matrix of each processor
24808  Vector<Vector<Vector<Vector<unsigned> > > > local_adjacency_matrix(nproc);
24809 
24810  // Loop over all the processors
24811  for (unsigned iproc = 0; iproc < nproc; iproc++)
24812  {
24813  local_node_alias[iproc].resize(nproc);
24814 
24815  // Resize the local adjacency matrix to store the info. sent
24816  // from all processors
24817  local_adjacency_matrix[iproc].resize(nproc);
24818 
24819  if (n_unsigned_data_received_in_root[iproc] > 0)
24820  {
24821  // Loop over all the processors to decode the info. received
24822  // from each one
24823  for (unsigned jproc = 0; jproc < nproc; jproc++)
24824  {
24825  // Read the processor number to which the info. correspond
24826  const unsigned read_jproc =
24827  package_unsigned_data_received_root[decode_counter++];
24828 
24829  // The read processor must be the same as the jproc, if that
24830  // is not the case then there is a synchronisation issue
24831  if (read_jproc != jproc)
24832  {
24833  std::ostringstream error_stream;
24834  error_stream
24835  << "The read processor is different from the jproc, this is\n"
24836  << "a synchronisation issue. The data are not read in the\n"
24837  << "sameorder as the were packaged\n"
24838  << "Read processor: (" << read_jproc << ")\n"
24839  << "Current jproc: (" << jproc << ")\n\n";
24840  throw OomphLibError(error_stream.str(),
24841  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
24842  OOMPH_EXCEPTION_LOCATION);
24843  }
24844 
24845  // Read the number of nodes in the shared boundaries between
24846  // iproc and jproc
24847  const unsigned read_n_shd_nodes_iproc_jproc =
24848  package_unsigned_data_received_root[decode_counter++];
24849 
24850  // Resize the container
24851  local_node_alias[iproc][jproc].resize(read_n_shd_nodes_iproc_jproc);
24852 
24853  // Loop over the number of nodes shared between iproc and
24854  // jproc
24855  for (unsigned ishd = 0; ishd < read_n_shd_nodes_iproc_jproc; ishd++)
24856  {
24857  // Read the number of alias of the current ishd node
24858  const unsigned read_n_alias_node_iproc_jproc =
24859  package_unsigned_data_received_root[decode_counter++];
24860 
24861  // Resize the container
24862  local_node_alias[iproc][jproc][ishd].
24863  resize(read_n_alias_node_iproc_jproc);
24864 
24865  for (unsigned ialias = 0;
24866  ialias < read_n_alias_node_iproc_jproc; ialias++)
24867  {
24868  // Resize the container, we know there are three data to
24869  // define the alias of a node
24870  local_node_alias[iproc][jproc][ishd][ialias].resize(3);
24871 
24872  // The 1st processor with which is shared
24873  local_node_alias[iproc][jproc][ishd][ialias][0] =
24874  package_unsigned_data_received_root[decode_counter++];
24875 
24876  // The 2nd processor with which is shared
24877  local_node_alias[iproc][jproc][ishd][ialias][1] =
24878  package_unsigned_data_received_root[decode_counter++];
24879 
24880  // The index of the node in the interaction iproc-jproc
24881  local_node_alias[iproc][jproc][ishd][ialias][2] =
24882  package_unsigned_data_received_root[decode_counter++];
24883 
24884  } // for (ialias < read_n_alias_node_iproc_jproc)
24885 
24886  } // for (ishd < read_n_shd_nodes_iproc_jproc)
24887 
24888  // Resize the local adjacency matrix
24889  local_adjacency_matrix[iproc][jproc].
24890  resize(read_n_shd_nodes_iproc_jproc);
24891  // Read the adjacency matrix sent to root processor
24892  for (unsigned i = 0; i < read_n_shd_nodes_iproc_jproc; i++)
24893  {
24894  // Resize the local adjacency matrix
24895  local_adjacency_matrix[iproc][jproc][i].
24896  resize(read_n_shd_nodes_iproc_jproc);
24897  for (unsigned j = 0; j < read_n_shd_nodes_iproc_jproc; j++)
24898  {
24899  // Read the adjacency matrix entry
24900  local_adjacency_matrix[iproc][jproc][i][j] =
24901  package_unsigned_data_received_root[decode_counter++];
24902  } // for (j < read_n_shd_nodes_iproc_jproc)
24903 
24904  } // for (i < read_n_shd_nodes_iproc_jproc)
24905 
24906  } // for (jproc < nproc)
24907 
24908  } // for (iproc < nproc)
24909 
24910  } // for (iproc < nproc)
24911 
24912 #ifdef PARANOID
24913  if (decode_counter != n_unsigned_total_data_receive_in_root)
24914  {
24915  std::ostringstream error_stream;
24916  error_stream
24917  << "The number of data decoded in root received from others\n"
24918  << "processors is different from the total number of data received\n"
24919  << "Data decoded: (" << decode_counter << ")\n"
24920  << "Data received: ("<<n_unsigned_total_data_receive_in_root<<")\n\n"
24921  << "This is a synchronisation issue so you are probably sending\n"
24922  << "more or less info. than the one that is being decoded\n\n";
24923  throw OomphLibError(error_stream.str(),
24924  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
24925  OOMPH_EXCEPTION_LOCATION);
24926  }
24927 #endif
24928 
24929  // Assign a unique id to the nodes (uses the alias information to
24930  // identify the repetition of a node in other processors). The
24931  // global node id is given by the position (index) in the global
24932  // node alias
24933 
24934  // Keep track of those alias already assigned a unique id
24935  std::map<Vector<unsigned>, bool> alias_done;
24936 
24937  // Store all the alias associated to each node
24938  Vector<Vector<Vector<unsigned> > > global_node_alias;
24939 
24940  // Loop over all the processors
24941  for (unsigned iproc = 0; iproc < nproc; iproc++)
24942  {
24943  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
24944  {
24945  // Read the number of nodes shared between the processors
24946  const unsigned n_shd_nodes_iproc_jproc =
24947  local_node_alias[iproc][jproc].size();
24948 #ifdef PARANOID
24949  // Read the number of nodes shared in the other direction
24950  const unsigned n_shd_nodes_jproc_iproc =
24951  local_node_alias[jproc][iproc].size();
24952 
24953  if (n_shd_nodes_iproc_jproc != n_shd_nodes_jproc_iproc)
24954  {
24955  std::ostringstream error_stream;
24956  error_stream
24957  << "The number of nodes shared between iproc and jproc is\n"
24958  << "different from the number of nodes shared between jproc\n"
24959  << "and iproc\n"
24960  << "Nodes shared between processor (" << iproc << ") and "
24961  << "processor ("<<jproc<<"): ("<<n_shd_nodes_iproc_jproc<<")\n"
24962  << "Nodes shared between processor (" << jproc << ") and "
24963  << "processor ("<<iproc<<"): ("<<n_shd_nodes_jproc_iproc<<")\n\n";
24964  throw OomphLibError(error_stream.str(),
24965  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
24966  OOMPH_EXCEPTION_LOCATION);
24967  } // if (n_shd_nodes_iproc_jproc != n_shd_nodes_jproc_iproc)
24968 #endif
24969 
24970  // Loop over the nodes shared between the processors
24971  for (unsigned ishd = 0; ishd < n_shd_nodes_iproc_jproc; ishd++)
24972  {
24973  // Get the number of alias associated to the node on each
24974  // processor
24975  const unsigned n_alias_iproc_jproc =
24976  local_node_alias[iproc][jproc][ishd].size();
24977  const unsigned n_alias_jproc_iproc =
24978  local_node_alias[jproc][iproc][ishd].size();
24979 
24980  // Store all the found alias to the node
24981  Vector<Vector<unsigned> > node_alias;
24982 
24983  // Flag to indicate if a new alias has been added
24984  bool new_alias_added = false;
24985 
24986  // Start by adding the "direct" alias of the node
24987  for (unsigned ialias = 0; ialias < n_alias_iproc_jproc; ialias++)
24988  {
24989  // Get the alias of the node
24990  Vector<unsigned> current_alias =
24991  local_node_alias[iproc][jproc][ishd][ialias];
24992  // Check if already done
24993  if (!alias_done[current_alias])
24994  {
24995  // Add the alias of the node
24996  node_alias.push_back(current_alias);
24997  // Set the flag to indicate a new alias has been added
24998  new_alias_added = true;
24999  // Mark the alias as done
25000  alias_done[current_alias] = true;
25001  } // if (!alias_done[i_alias])
25002 
25003  } // for (ialias < n_alias_iproc_jproc)
25004 
25005  // Start by adding the "direct" alias of the node
25006  for (unsigned ialias = 0; ialias < n_alias_jproc_iproc; ialias++)
25007  {
25008  // Get the alias of the node
25009  Vector<unsigned> current_alias =
25010  local_node_alias[jproc][iproc][ishd][ialias];
25011 
25012  // Check if already done
25013  if (!alias_done[current_alias])
25014  {
25015  // Add the alias of the node
25016  node_alias.push_back(current_alias);
25017  // Set the flag to indicate a new alias has been added
25018  new_alias_added = true;
25019  // Mark the alias as done
25020  alias_done[current_alias] = true;
25021  } // if (!alias_done[i_alias])
25022 
25023  } // for (ialias < n_alias_jproc_iproc)
25024 
25025  unsigned counter_alias = 0;
25026  // Visit the alias of the node and add any new found
25027  // alias, end until all its alias have been included
25028 
25029  unsigned n_current_alias = node_alias.size();
25030  while(new_alias_added || counter_alias < n_current_alias)
25031  //while(new_alias_added) // we need to check all the alias, including those added during the process
25032  {
25033  new_alias_added = false;
25034  // Store the current visited alias
25035  Vector<unsigned> current_alias = node_alias[counter_alias];
25036 
25037  // Get the alias associated with the current alias
25038  Vector<Vector<unsigned> > alias_of_current_alias =
25039  local_node_alias[current_alias[0]]
25040  [current_alias[1]]
25041  [current_alias[2]];
25042 
25043  // Get all the alias associated with the alias of the
25044  // current alias
25045  const unsigned n_alias = alias_of_current_alias.size();
25046 
25047  // Loop over the new alias and check if require to add
25048  // them
25049  for (unsigned k = 0; k < n_alias; k++)
25050  {
25051  // Get the alias of the node
25052  Vector<unsigned> add_alias =
25053  alias_of_current_alias[k];
25054 
25055  // Check if already done
25056  if (!alias_done[add_alias])
25057  {
25058  // Add the alias of the node
25059  node_alias.push_back(add_alias);
25060  // Set the flag to indicate a new alias has been
25061  // added
25062  new_alias_added = true;
25063  // Mark the alias ad done
25064  alias_done[add_alias] = true;
25065  } // if (!alias_done[i_alias])
25066 
25067  } // for (k < n_alias)
25068 
25069  // Get the alias associated with the current alias (in the
25070  // other direction)
25071  Vector<Vector<unsigned> > alias_of_current_alias2 =
25072  local_node_alias[current_alias[1]]
25073  [current_alias[0]]
25074  [current_alias[2]];
25075 
25076  // Get all the alias associated with the current alias
25077  // (in the other direction)
25078  const unsigned n_alias2 = alias_of_current_alias2.size();
25079 
25080  // Loop over the new alias and check if require to add
25081  // them
25082  for (unsigned k = 0; k < n_alias2; k++)
25083  {
25084  // Get the alias of the node
25085  Vector<unsigned> add_alias =
25086  alias_of_current_alias2[k];
25087 
25088  // Check if already done
25089  if (!alias_done[add_alias])
25090  {
25091  // Add the alias of the node
25092  node_alias.push_back(add_alias);
25093  // Set the flag to indicate a new alias has been
25094  // added
25095  new_alias_added = true;
25096  // Mark the alias ad done
25097  alias_done[add_alias] = true;
25098  } // if (!alias_done[i_alias])
25099 
25100  } // for (k < n_alias)
25101 
25102  // Go for the next alias
25103  counter_alias++;
25104 
25105  // Update the number of alias so that the while stops when
25106  // all the alias have been visited and no new alias was
25107  // added
25108  n_current_alias = node_alias.size();
25109 
25110  } // while(new_alias_added || counter_alias < n_current_alias)
25111 
25112  // If the node has not been previously added, then include
25113  // all its alias
25114  if (node_alias.size() > 0)
25115  {
25116  // Add all the found alias of the node to the global alias
25117  // storage
25118  global_node_alias.push_back(node_alias);
25119  }
25120 
25121  } // for (ishd < n_shd_nodes_iproc_jproc)
25122 
25123  } // for (jproc < nproc)
25124 
25125  } // for (iproc < nproc)
25126 
25127  // We now have the global number of nodes, each with its own id
25128  // (the index in the global_node_alias vector)
25129 
25130  // Get the number of global shared nodes
25131  const unsigned n_global_shared_nodes = global_node_alias.size();
25132 
25133  // Create matrix from local to global shared node id
25134  Vector<Vector<Vector<int> > > local_to_global_shared_node(nproc);
25135 
25136  // Loop over all the processors to resize
25137  for (unsigned iproc = 0; iproc < nproc; iproc++)
25138  {
25139  // Resize the map matrix
25140  local_to_global_shared_node[iproc].resize(nproc);
25141  } // for (iproc < nproc)
25142 
25143  // Loop over all the processors to resize (the third direction,
25144  // required if we want to loop over the half of the matrix only)
25145  for (unsigned iproc = 0; iproc < nproc; iproc++)
25146  {
25147  // Loop over the half of the matrix to resize
25148  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25149  {
25150  // Read the number of nodes shared between the processors
25151  const unsigned n_shd_nodes =
25152  local_node_alias[iproc][jproc].size();
25153 
25154  // Resize the map matrix
25155  local_to_global_shared_node[iproc][jproc].resize(n_shd_nodes,-1);
25156 
25157  // ... and resize the other half map matrix
25158  local_to_global_shared_node[jproc][iproc].resize(n_shd_nodes,-1);
25159 
25160  } // for (jproc < nproc)
25161 
25162  } // for (iproc < nproc)
25163 
25164  // Fill the matrix for mapping from local to global node id
25165 
25166  // Loop over the global nodes, and for each alias assign the
25167  // corresponding global node id
25168  for (unsigned k = 0 ; k < n_global_shared_nodes; k++)
25169  {
25170  // Get the number of alias associated to the current global node
25171  const unsigned n_alias_global_node = global_node_alias[k].size();
25172  // Loop over the alias and assign the global node id
25173  for (unsigned l = 0; l < n_alias_global_node; l++)
25174  {
25175  // Get the 1st processor
25176  const unsigned iproc = global_node_alias[k][l][0];
25177  // Get the 2nd processor
25178  const unsigned jproc = global_node_alias[k][l][1];
25179  // Get the node number
25180  const unsigned ishd = global_node_alias[k][l][2];
25181  // Assign the global node id
25182  local_to_global_shared_node[iproc][jproc][ishd] = k;
25183 
25184  } // for (l < n_alias_global_node)
25185 
25186  } // for (k < n_global_shared_nodes)
25187 
25188  // Create the global adjacency matrix
25189  Vector<Vector<unsigned> > global_adjacency_matrix(n_global_shared_nodes);
25190  // Resize the global adjacency matrix
25191  for (unsigned k = 0; k < n_global_shared_nodes; k++)
25192  {
25193  // Resize
25194  global_adjacency_matrix[k].resize(n_global_shared_nodes,0);
25195  } // for (k < n_global_shared_nodes)
25196 
25197  // Add the entries to the global adjacency matrix and compute the
25198  // degree of each node
25199 
25200  // Store the degree of the global nodes
25201  Vector<unsigned> global_node_degree(n_global_shared_nodes, 0);
25202 
25203  // Loop over the processors
25204  for (unsigned iproc = 0; iproc < nproc; iproc++)
25205  {
25206  // Loop over the half of the matrix to resize
25207  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25208  {
25209  // Get the number of nodes shared between the processors
25210  const unsigned n_shd_nodes =
25211  local_node_alias[iproc][jproc].size();
25212 
25213  // Search for entries in the local adjacency matrix that set a
25214  // connection among the nodes
25215 
25216  // Loop over the shared nodes in the current pair of
25217  // processors
25218  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25219  {
25220  for (unsigned jshd = ishd + 1; jshd < n_shd_nodes; jshd++)
25221  {
25222  // Are the nodes associated
25223  if (local_adjacency_matrix[iproc][jproc][ishd][jshd] > 0)
25224  {
25225  // Get the global nodes id
25226 
25227  // Get the "left-node" global id
25228  const int global_shd_node_left =
25229  local_to_global_shared_node[iproc][jproc][ishd];
25230 
25231  // Get the "right-node" global id
25232  const int global_shd_node_right =
25233  local_to_global_shared_node[iproc][jproc][jshd];
25234 
25235 #ifdef PARANOID
25236  // Check if the local nodes have a global node
25237  // associated
25238  if (global_shd_node_left == -1)
25239  {
25240  std::ostringstream error_stream;
25241  error_stream
25242  << "The local node in processors iproc and jproc has no\n"
25243  << "global node assigned\n"
25244  << "iproc processor: (" << iproc << ")\n"
25245  << "jproc processor: ("<<jproc<<")\n"
25246  << "Local node: (" << ishd << ")\n\n";
25247  throw OomphLibError(error_stream.str(),
25248  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25249  OOMPH_EXCEPTION_LOCATION);
25250  }
25251 
25252  // Check if the local nodes have a global node
25253  // associated
25254  if (global_shd_node_right == -1)
25255  {
25256  std::ostringstream error_stream;
25257  error_stream
25258  << "The local node in processors iproc and jproc has no\n"
25259  << "global node assigned\n"
25260  << "iproc processor: (" << iproc << ")\n"
25261  << "jproc processor: ("<<jproc<<")\n"
25262  << "Local node: (" << jshd << ")\n\n";
25263  throw OomphLibError(error_stream.str(),
25264  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25265  OOMPH_EXCEPTION_LOCATION);
25266  }
25267 #endif
25268  // Get the unsigned version of the indexes
25269  const unsigned uleft =
25270  static_cast<unsigned>(global_shd_node_left);
25271  const unsigned uright =
25272  static_cast<unsigned>(global_shd_node_right);
25273 
25274  // Add the entry in the global adjacency matrix
25275  global_adjacency_matrix[uleft][uright]++;
25276 
25277  // ... and in the other direction too
25278  global_adjacency_matrix[uright][uleft]++;
25279 
25280  // Add on to the degree of the left node
25281  global_node_degree[uleft]++;
25282 
25283  // Add on to the degree of the right node
25284  global_node_degree[uright]++;
25285 
25286  } // if (local_adjacency_matrix[iproc][jproc][ishd][jshd] > 0)
25287 
25288  } // // for (jshd < n_shd_nodes)
25289 
25290  } // for (ishd < n_shd_nodes)
25291 
25292  } // for (jproc < nproc)
25293 
25294  } // for (iproc < nproc)
25295 
25296  // Assign the global degree to the shared nodes between each pair
25297  // of processors
25298  Vector<Vector<Vector<unsigned> > > root_local_node_degree(nproc);
25299  // Resize the container
25300  for (unsigned iproc = 0; iproc < nproc; iproc++)
25301  {
25302  root_local_node_degree[iproc].resize(nproc);
25303  }
25304 
25305  // Loop over the processors and visited their shared nodes
25306  for (unsigned iproc = 0; iproc < nproc; iproc++)
25307  {
25308  // Only visit the half of the data
25309  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25310  {
25311  // Get the number of shared nodes between this pair of
25312  // processors (iproc, jproc)
25313  const unsigned n_shd_nodes = local_node_alias[iproc][jproc].size();
25314 
25315  // Resize the container to store the local degree of the nodes
25316  root_local_node_degree[iproc][jproc].resize(n_shd_nodes);
25317  // ... and in the other way too
25318  root_local_node_degree[jproc][iproc].resize(n_shd_nodes);
25319 
25320  // Loop over the number of nodes shared between the pair of
25321  // processors
25322  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25323  {
25324  // Get the global node id for the current shared node
25325  const int global_shd_node_id =
25326  local_to_global_shared_node[iproc][jproc][ishd];
25327 
25328 #ifdef PARANOID
25329  // Check if the local nodes have a global node associated
25330  if (global_shd_node_id == -1)
25331  {
25332  std::ostringstream error_stream;
25333  error_stream
25334  << "The local node in processors iproc and jproc has no\n"
25335  << "global node assigned\n"
25336  << "iproc processor: (" << iproc << ")\n"
25337  << "jproc processor: ("<<jproc<<")\n"
25338  << "Local node: (" << ishd << ")\n\n";
25339  throw OomphLibError(error_stream.str(),
25340  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25341  OOMPH_EXCEPTION_LOCATION);
25342  }
25343 #endif
25344 
25345  // Get the unsigned version of the global index
25346  const unsigned uglobal_shd_node_id =
25347  static_cast<unsigned>(global_shd_node_id);
25348 
25349  // Get the degree of the node
25350  const unsigned node_degree =
25351  global_node_degree[uglobal_shd_node_id];
25352 
25353  // Set the degree in the container for the degree of the
25354  // nodes in the local interaction between processors
25355  root_local_node_degree[iproc][jproc][ishd] = node_degree;
25356  // ... and in the other way too
25357  root_local_node_degree[jproc][iproc][ishd] = node_degree;
25358 
25359  } // for (ishd < n_shd_nodes)
25360 
25361  } // for (jproc < nproc)
25362 
25363  } // for (iproc < nproc)
25364 
25365  // Clear the container where the info. will be sent back to each
25366  // processor
25367  package_unsigned_data_sent_from_root.clear();
25368 
25369  // Prepare the data to sent it back to each processor (encode the
25370  // info. to sent to all processors)
25371  for (unsigned iproc = 0; iproc < nproc; iproc++)
25372  {
25373  // Count the number of data sent to iproc processor
25374  unsigned count_n_data_sent_to_iproc = 0;
25375  for (unsigned jproc = 0; jproc < nproc; jproc++)
25376  {
25377  // No shared nodes between the same processor
25378  if (iproc != jproc)
25379  {
25380  // Get the number of nodes shared between the processors
25381  const unsigned n_shd_nodes =
25382  root_local_node_degree[iproc][jproc].size();
25383 
25384  // Add the number of data sent to iproc processor
25385  count_n_data_sent_to_iproc+=n_shd_nodes;
25386 
25387  // Loop over the nodes shared between the pair of processors
25388  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25389  {
25390  package_unsigned_data_sent_from_root.
25391  push_back(root_local_node_degree[iproc][jproc][ishd]);
25392  } // for (ishd < n_shd_nodes)
25393 
25394  } // if (iproc != jproc)
25395 
25396  } // for (jproc < nproc)
25397 
25398  // Set the number of data sent to iproc processor
25399  n_unsigned_data_sent_from_root[iproc] = count_n_data_sent_to_iproc;
25400 
25401  } // for (iproc < nproc)
25402 
25403  } // if (my_rank == root_processor)
25404 
25405  // Total data received from root to this processor
25406  int n_unsigned_data_received_from_root = 0;
25407 
25408  // Get the number of data that each processor receives from root
25409  MPI_Scatter(&n_unsigned_data_sent_from_root[0], // Info. sent from
25410  // root to each
25411  // processor
25412  1, // The number of data sent from root to each
25413  // processor
25414  MPI_UNSIGNED,
25415  &n_unsigned_data_received_from_root, // Store the
25416  // info. received
25417  // from root
25418  1, // The number of data received from root
25419  MPI_UNSIGNED,
25420  root_processor, // The processor that sends the
25421  // info.
25422  comm_pt->mpi_comm());
25423 
25424  // Receive the info. sent by root
25426  package_unsigned_data_received_from_root(n_unsigned_data_received_from_root);
25427 
25428  // Compute the offsets to each processor
25429  Vector<int> root_unsigned_offsets_sent(nproc,0);
25430  root_unsigned_offsets_sent[0] = 0;
25431  for (unsigned iproc = 1; iproc < nproc; iproc++)
25432  {
25433  // Compute the offset to send the values to each processor
25434  root_unsigned_offsets_sent[iproc] =
25435  root_unsigned_offsets_sent[iproc-1] +
25436  n_unsigned_data_sent_from_root[iproc-1];
25437  }
25438 
25439  if (my_rank!=root_processor)
25440  {
25441  // Create at least one entry so we don't get a seg fault below
25442  if (package_unsigned_data_sent_from_root.size()==0)
25443  {
25444  package_unsigned_data_sent_from_root.resize(1);
25445  }
25446  } // if (my_rank!=root_processor)
25447 
25448  // Create at least one entry so we don't get a seg fault below
25449  if (package_unsigned_data_received_from_root.size()==0)
25450  {
25451  package_unsigned_data_received_from_root.resize(1);
25452  }
25453 
25454  // Get the data from root
25455  MPI_Scatterv(&package_unsigned_data_sent_from_root[0], // The
25456  // info. sent
25457  // from root
25458  // to others
25459  // processors
25460  &n_unsigned_data_sent_from_root[0], // The number of
25461  // data sent from
25462  // root to others
25463  // processors
25464  &root_unsigned_offsets_sent[0], // The offsets to each
25465  // processors
25466  MPI_UNSIGNED,
25467  &package_unsigned_data_received_from_root[0], // The
25468  // storage
25469  // in the
25470  // processor
25471  // that
25472  // receives
25473  // the
25474  // info.
25475  n_unsigned_data_received_from_root, // The number of
25476  // data that the
25477  // current
25478  // processor
25479  // receives from
25480  // root
25481  MPI_UNSIGNED,
25482  root_processor, // The root processors
25483  comm_pt->mpi_comm());
25484 
25485  // Decode the info.
25486 
25487  // Keep track of the already nodes done
25488  std::map<Node*, bool> node_done;
25489 
25490  // Read the global degree assigned to the shared nodes between the
25491  // current processors and the other processors
25492  int decode_counter = 0;
25493  // Store the global degree of the local nodes
25494  Vector<Vector<unsigned> > local_node_degree(nproc);
25495  // Loop over the processors
25496  for (unsigned iproc = 0; iproc < nproc; iproc++)
25497  {
25498  // There are no shared nodes with the current processor itself
25499  if (iproc != my_rank)
25500  {
25501  // Get the number of nodes shared with the iproc processor
25502  const unsigned n_nodes = tmp_sorted_shared_node_pt[iproc].size();
25503 
25504  // Read the global degree of the node
25505  package_unsigned_send_data_to_root.push_back(n_nodes);
25506 
25507  // Loop over the nodes
25508  for (unsigned ishd = 0; ishd < n_nodes; ishd++)
25509  {
25510  // Get the node degree assigned to the ishd node in between
25511  // the interaction of the iproc and the current processor
25512  const unsigned node_degree =
25513  package_unsigned_data_received_from_root[decode_counter++];
25514 
25515  // Get the node
25516  Node* shd_node_pt =
25517  tmp_sorted_shared_node_pt[iproc][ishd];
25518 
25519  // Has the node been assigned a global degree
25520  if (!node_done[shd_node_pt])
25521  {
25522  // Assign the global degree to the node
25523  global_node_degree[shd_node_pt] = node_degree;
25524  // Mark the node as done
25525  node_done[shd_node_pt] = true;
25526  }
25527 #ifdef PARANOID
25528  else
25529  {
25530  // The node has been already done, check that the node
25531  // degree is the same as the already assigned
25532  if (global_node_degree[shd_node_pt] != node_degree)
25533  {
25534  std::ostringstream error_stream;
25535  error_stream
25536  << "The local node has already assigned a global degree,\n"
25537  << "however, a different degree for the same node has been\n"
25538  << "read from the data sent from root processor\n"
25539  << "iproc processor: (" << iproc << ")\n"
25540  << "Local node: (" << ishd << ")\n"
25541  << "---------------------------------------------------------\n"
25542  << "Already assigned degree: ("
25543  << global_node_degree[shd_node_pt] << ")\n"
25544  << "New found degree: (" << node_degree << ")\n"
25545  << "---------------------------------------------------------\n"
25546  << "Node coordinates: (" << shd_node_pt->x(0) << ", "
25547  << shd_node_pt->x(1) << ")\n\n";
25548  throw OomphLibError(error_stream.str(),
25549  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25550  OOMPH_EXCEPTION_LOCATION);
25551  }
25552 
25553  } // else if (!node_done[shd_node_pt])
25554 #endif // #ifdef PARANOID
25555 
25556  } // for (ishd < n_nodes)
25557 
25558  } // if (iproc != my_rank)
25559 
25560  } // for (iproc < nproc)
25561 
25562 #ifdef PARANOID
25563  // Ensure that all the info. sent from root processor has been read
25564  if (decode_counter != n_unsigned_data_received_from_root)
25565  {
25566  std::ostringstream error_stream;
25567  error_stream
25568  << "The number of data decoded received from root processor is\n"
25569  << "different from the total number of data received from the root\n"
25570  << "processor\n"
25571  << "Data decoded: (" << decode_counter << ")\n"
25572  << "Data received: ("<<n_unsigned_data_received_from_root<<")\n\n"
25573  << "This is a synchronisation issue so you are probably sending\n"
25574  << "more or less info. than the one that is being decoded\n\n";
25575  throw OomphLibError(error_stream.str(),
25576  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25577  OOMPH_EXCEPTION_LOCATION);
25578  }
25579 #endif
25580 
25581  }
25582 
25583  //======================================================================
25584  // Sort the nodes on the new shared boundaries (after load balancing),
25585  // computes the alias of the nodes and creates the adjacency matrix
25586  // that represent the graph created by the shared edges between each
25587  // pair of processors
25588  // ======================================================================
25589  template <class ELEMENT>
25592  Vector<Vector<FiniteElement*> > &unsorted_face_ele_pt,
25593  Vector<Vector<Node*> > &tmp_sorted_shared_node_pt,
25594  std::map<Node*, Vector<Vector<unsigned> > > &node_alias,
25595  Vector<Vector<Vector<unsigned> > > &adjacency_matrix)
25596  {
25597  // Get the number of processors and the rank
25598  const unsigned nproc = this->communicator_pt()->nproc();
25599  const unsigned my_rank = this->communicator_pt()->my_rank();
25600 
25601  // Assign a unique id to each node shared between each pair of
25602  // processors, in this case the current processor and the iproc
25603 
25604  // ... also compute the alias of each node (processor and index of
25605  // the node in all processors where it appears)
25606 
25607  // Clear the alias info
25608  node_alias.clear();
25609 
25610  // Temporary storage for the index of the nodes
25611  Vector<std::map<Node*, unsigned> > tmp_node_index(nproc);
25612 
25613  // Loop over the processors
25614  for (unsigned iproc = 0; iproc < nproc; iproc++)
25615  {
25616  // There is no shared elements between the same processor
25617  if (iproc != my_rank)
25618  {
25619  // Map to mark those nodes already visited
25620  std::map<Node*, bool> done_node;
25621 
25622  // A map is used to sort the nodes using their coordinates as
25623  // the key of the map
25624  //std::map<std::pair<double, double>, Node*> sorted_nodes_pt;
25625  std::map<std::pair<double, double>, Node*, classcomp> sorted_nodes_pt;
25626 
25627  // Get the number of unsorted face elements
25628  const unsigned n_unsorted_face_ele =
25629  unsorted_face_ele_pt[iproc].size();
25630 
25631  // Loop over the unsorted elements
25632  for (unsigned e = 0; e < n_unsorted_face_ele; e++)
25633  {
25634  // Get a root element
25635  FiniteElement* face_ele_pt = unsorted_face_ele_pt[iproc][e];
25636  // Get the left node of the face element
25637  Node* left_node_pt = face_ele_pt->node_pt(0);
25638 
25639  // Check if the node has been already sorted in the
25640  // interaction between the current processor and iproc
25641  // processor
25642  if (!done_node[left_node_pt])
25643  {
25644  std::pair<double, double> vertex =
25645  std::make_pair(left_node_pt->x(0), left_node_pt->x(1));
25646  sorted_nodes_pt[vertex] = left_node_pt;
25647  // Mark the node as done
25648  done_node[left_node_pt] = true;
25649  }
25650 
25651  // Get the number of nodes of the face element
25652  const unsigned n_nodes = face_ele_pt->nnode();
25653  // Get the right node of the face element
25654  Node* right_node_pt = face_ele_pt->node_pt(n_nodes-1);
25655 
25656  // Check if the node has been already sorted in the
25657  // interaction between the current processor and iproc
25658  // processor
25659  if (!done_node[right_node_pt])
25660  {
25661  std::pair<double, double> vertex =
25662  std::make_pair(right_node_pt->x(0), right_node_pt->x(1));
25663  sorted_nodes_pt[vertex] = right_node_pt;
25664  // Mark the node as done
25665  done_node[right_node_pt] = true;
25666  }
25667 
25668  } // for (e < nunsorted_face_ele)
25669 
25670  // The nodes are already sorted, we need to return them in the
25671  // proper container
25672 
25673  // The counter to enumerate the nodes
25674  unsigned counter = 0;
25675 
25676  // Go through the map container which already have the nodes
25677  // sorted they have the same sorting on all processors
25678  for (std::map<std::pair<double, double>, Node*>::iterator it
25679  = sorted_nodes_pt.begin(); it != sorted_nodes_pt.end(); it++)
25680  {
25681  // Get the node
25682  Node* node_pt = (*it).second;
25683  // Store the node at the corresponding index
25684  tmp_sorted_shared_node_pt[iproc].push_back(node_pt);
25685 
25686  // Create the temporary access to the node index
25687  tmp_node_index[iproc][node_pt] = counter;
25688 
25689  // Fill the info. for the node alias
25690  Vector<unsigned> alias(3);
25691  // The current processor
25692  alias[0] = my_rank;
25693  // The processor with which is shared
25694  alias[1] = iproc;
25695  // The index with that processor
25696  alias[2] = counter++;
25697 
25698  // Store the info. of the alias
25699  node_alias[node_pt].push_back(alias);
25700 
25701  } // Loop map
25702 
25703  } // if (iproc != my_rank)
25704 
25705  } // for (iproc < nproc)
25706 
25707  // Loop over the processors to resize and initialize the adjacency
25708  // matrix
25709  for (unsigned iproc = 0 ; iproc < nproc; iproc++)
25710  {
25711  // Get the number of nodes shared with iproc
25712  const unsigned n_shd_nodes = tmp_sorted_shared_node_pt[iproc].size();
25713  // Resize the adjacency matrix
25714  adjacency_matrix[iproc].resize(n_shd_nodes);
25715  for (unsigned i = 0; i < n_shd_nodes; i++)
25716  {
25717  // Resize the adjacency matrix
25718  adjacency_matrix[iproc][i].resize(n_shd_nodes);
25719 
25720  // Initialize the
25721  for (unsigned j = 0; j < n_shd_nodes; j++)
25722  {
25723  adjacency_matrix[iproc][i][j] = 0;
25724  } // for (j < n_shd_nodes)
25725 
25726  } // for (i < n_shd_nodes)
25727 
25728  } // for (iproc < nproc)
25729 
25730  // Loop over the processors to fill the adjacency matrix
25731  for (unsigned iproc = 0 ; iproc < nproc; iproc++)
25732  {
25733  // There is no shared elements between the same processor
25734  if (iproc != my_rank)
25735  {
25736  // Get the number of unsorted face elements
25737  const unsigned n_unsorted_face_ele =
25738  unsorted_face_ele_pt[iproc].size();
25739 
25740  // Loop over the unsorted elements
25741  for (unsigned e = 0; e < n_unsorted_face_ele; e++)
25742  {
25743  // Get a root element
25744  FiniteElement* face_ele_pt = unsorted_face_ele_pt[iproc][e];
25745  // Get the left node of the face element
25746  Node* left_node_pt = face_ele_pt->node_pt(0);
25747 
25748  // Get the number of nodes of the face element
25749  const unsigned n_nodes = face_ele_pt->nnode();
25750  // Get the right node of the face element
25751  Node* right_node_pt = face_ele_pt->node_pt(n_nodes-1);
25752 
25753  // Get the index of each of the nodes
25754  const unsigned left_node_index = tmp_node_index[iproc][left_node_pt];
25755  const unsigned right_node_index = tmp_node_index[iproc][right_node_pt];
25756 
25757  // Add an entry to the adjacency matrix to indicate the
25758  // association of left and right node
25759  adjacency_matrix[iproc][left_node_index][right_node_index]++;
25760  // ... both directions
25761  adjacency_matrix[iproc][right_node_index][left_node_index]++;
25762 
25763  } // for (e < n_unsorted_face_ele)
25764 
25765  } // if (iproc != my_rank)
25766 
25767  } // for (iproc < nproc)
25768 
25769  }
25770 
25771  //======================================================================
25772  /// \short Get the nodes on the shared boundary (b), these are stored
25773  /// in the segment they belong
25774  //======================================================================
25775  template <class ELEMENT>
25778  const unsigned &shd_bnd_id, Vector<Vector<Node*> > &tmp_segment_nodes)
25779  {
25780  // Clear the data structure were to return the nodes
25781  tmp_segment_nodes.clear();
25782 
25783  // Get the face elements that created the shared boundary from the
25784  // bulk shared boundary elements
25785 
25786 #ifdef PARANOID
25787  // The temporary storage for the halo face elements
25788  Vector<FiniteElement*> halo_shared_face_ele_pt;
25789 #endif
25790  // The temporary storage for the nonhalo face elements
25791  Vector<FiniteElement*> nonhalo_shared_face_ele_pt;
25792 
25793  // Get the number of shared boundary elements associated with the
25794  // current shared boundary
25795  const unsigned nshared_bound_ele =
25796  this->nshared_boundary_element(shd_bnd_id);
25797 
25798  // Loop over the elements in the shared boundary to create the face
25799  // elements
25800  for (unsigned e = 0; e < nshared_bound_ele; e++)
25801  {
25802  // Get the shared boundary element
25803  FiniteElement* bulk_ele_pt =
25804  this->shared_boundary_element_pt(shd_bnd_id, e);
25805 
25806  // Get the face index
25807  int face_index = this->face_index_at_shared_boundary(shd_bnd_id, e);
25808 
25809  // Before adding the new element we need to ensure that the edge
25810  // that this element represents has not been already added
25811  FiniteElement* face_ele_pt =
25812  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
25813 
25814  // Nonhalo element
25815  if (!bulk_ele_pt->is_halo())
25816  {
25817  // Add nonhalo shared face element to the container
25818  nonhalo_shared_face_ele_pt.push_back(face_ele_pt);
25819  }
25820 #ifdef PARANOID
25821  else // halo element
25822  {
25823  // Add halo shared face element to the container
25824  halo_shared_face_ele_pt.push_back(face_ele_pt);
25825  }
25826 #endif
25827 
25828  } // for (e < nshared_bound_ele)
25829 
25830  // Mark the face elements already used
25831  std::map<FiniteElement*, bool> shared_face_done;
25832 
25833  // Get the number of nonhalo face elements
25834  const unsigned nnonhalo_face_shared_ele =
25835  nonhalo_shared_face_ele_pt.size();
25836 
25837  // If we are in PARANOID mode check that there is one halo element
25838  // for each nonhalo element
25839 #ifdef PARANOID
25840  // Get the number of halo face elements
25841  const unsigned nhalo_face_shared_ele =
25842  halo_shared_face_ele_pt.size();
25843 
25844  // The number of nonhalo shared face boundary elements must be the
25845  // half of the total number of shared boundary elements
25846  if (nshared_bound_ele / 2 != nnonhalo_face_shared_ele)
25847  {
25848  std::ostringstream error_message;
25849  error_message
25850  << "The number of shared boundary elements (" << nshared_bound_ele
25851  << ") is not the double\nof the number of unsorted nonhalo shared "
25852  << "face boundary elements (" << nnonhalo_face_shared_ele
25853  << ")\n for the current boundary ("<< shd_bnd_id << ")\n\n";
25854  throw OomphLibError(error_message.str(),
25855  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
25856  OOMPH_EXCEPTION_LOCATION);
25857  }
25858 
25859  // The number of halo shared face boundary elements must be the
25860  // half of the total number of shared boundary elements
25861  if (nshared_bound_ele / 2 != nhalo_face_shared_ele)
25862  {
25863  std::ostringstream error_message;
25864  error_message
25865  << "The number of shared boundary elements (" << nshared_bound_ele
25866  << ") is not the double\nof the number of unsorted halo shared "
25867  << "face boundary elements (" << nhalo_face_shared_ele
25868  << ")\n for the current boundary ("<< shd_bnd_id << ")\n\n";
25869  throw OomphLibError(error_message.str(),
25870  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
25871  OOMPH_EXCEPTION_LOCATION);
25872  }
25873 
25874  // ------------------------------------------------------------------
25875  // Loop over the nonhalo face elements and look for the halo face
25876  // element at the other side of the shared boundary
25877  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
25878  {
25879  // Get the inh-th face element
25880  FiniteElement* nonhalo_face_ele_pt = nonhalo_shared_face_ele_pt[inh];
25881 
25882  // Get the number of nodes on the face element
25883  const unsigned nnodes_nh = nonhalo_face_ele_pt->nnode();
25884  // Get the first and last node on the element
25885  Node* nh_first_node_pt = nonhalo_face_ele_pt->node_pt(0);
25886  Node* nh_last_node_pt = nonhalo_face_ele_pt->node_pt(nnodes_nh-1);
25887 
25888  // Now find the (halo) face element at the other side of the
25889  // shared boundary
25890  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
25891  {
25892  // Get the ih-th face element
25893  FiniteElement* halo_face_ele_pt = halo_shared_face_ele_pt[ih];
25894 
25895  // Check that the face element has not been done
25896  if (!shared_face_done[halo_face_ele_pt])
25897  {
25898  // Get the number of nodes on the face element
25899  const unsigned nnodes_h = halo_face_ele_pt->nnode();
25900  // Get the first and last node on the element
25901  Node* h_first_node_pt = halo_face_ele_pt->node_pt(0);
25902  Node* h_last_node_pt = halo_face_ele_pt->node_pt(nnodes_h-1);
25903 
25904  // If the nodes are the same then we have found the (halo)
25905  // face element at the other side of the shared boundary
25906  if (nh_first_node_pt == h_first_node_pt &&
25907  nh_last_node_pt == h_last_node_pt)
25908  {
25909  // Mark the face elements as done
25910  shared_face_done[nonhalo_face_ele_pt] = true;
25911  shared_face_done[halo_face_ele_pt] = true;
25912 
25913  // Break the loop for (ih < nhalo_face_shared_ele)
25914  break;
25915  } // if (nh_first_node_pt == h_first_node_pt &&
25916  // nh_last_node_pt == h_last_node_pt)
25917  else if (nh_first_node_pt == h_last_node_pt &&
25918  nh_last_node_pt == h_first_node_pt)
25919  {
25920  // Mark the face elements as done
25921  shared_face_done[nonhalo_face_ele_pt] = true;
25922  shared_face_done[halo_face_ele_pt] = true;
25923 
25924  // Break the loop for (ih < nhalo_face_shared_ele)
25925  break;
25926  } // else if (nh_first_node_pt == h_last_node_pt &&
25927  // nh_last_node_pt == h_first_node_pt)
25928 
25929  } // if (face_done[halo_face_ele_pt])
25930 
25931  } // for (ih < nhalo_face_shared_ele)
25932 
25933  } // for (inh < nnonhalo_face_shared_ele)
25934 
25935  // The number of done shared face elements MUST be the same as the
25936  // sum of the nonhalo and halo shared boundary face elements
25937  if ((nnonhalo_face_shared_ele + nhalo_face_shared_ele) !=
25938  shared_face_done.size())
25939  {
25940  std::ostringstream error_message;
25941  error_message
25942  << "The number of DONE shared boundary face elements ("
25943  << shared_face_done.size() << ") is not the same\n as the sum of"
25944  << "the nonhalo face shared boundary elements ("
25945  << nnonhalo_face_shared_ele << ")\nand the halo face shared "
25946  << "boundary elements ("<< nhalo_face_shared_ele << ") for the\n/"
25947  << "current boundary (" << shd_bnd_id << ")\n\n";
25948  throw OomphLibError(error_message.str(),
25949  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
25950  OOMPH_EXCEPTION_LOCATION);
25951  }
25952 #endif // #ifdef PARANOID
25953 
25954  // -------------------------------------------------------------
25955  // Now sort the face elements
25956  // -------------------------------------------------------------
25957 
25958  // We already have the shared face elements that make the shared
25959  // boundary now sort them to create a contiguous boundary
25960 
25961  // Clear the already done face elements
25962  shared_face_done.clear();
25963 
25964  unsigned nsorted_face_ele = 0;
25965 
25966  // Storing for the sorting nodes extracted from the face elements
25967  std::list<Node*> sorted_nodes;
25968 
25969  // Get the root face element
25970  FiniteElement* root_face_ele_pt = nonhalo_shared_face_ele_pt[0];
25971  nsorted_face_ele++;
25972 
25973  // Mark face as done
25974  shared_face_done[root_face_ele_pt] = true;
25975 
25976  // The initial and final node on the list
25977  const unsigned nnodes_root = root_face_ele_pt->nnode();
25978  Node *first_node_pt = root_face_ele_pt->node_pt(0);
25979  Node *last_node_pt = root_face_ele_pt->node_pt(nnodes_root-1);
25980 
25981  // Push back on the list the new nodes
25982  sorted_nodes.push_back(first_node_pt);
25983  sorted_nodes.push_back(last_node_pt);
25984 
25985  // Sort the face elements
25986  while (nsorted_face_ele < nnonhalo_face_shared_ele)
25987  {
25988  // Flag to indicate when a node was added
25989  bool node_added = false;
25990 
25991  // Start from the next edge since we have already added the
25992  // previous one as the initial face element
25993  for (unsigned iface = 1; iface < nnonhalo_face_shared_ele; iface++)
25994  {
25995  FiniteElement* tmp_shared_face_ele_pt =
25996  nonhalo_shared_face_ele_pt[iface];
25997 
25998  // If face has not been sorted
25999  if (!shared_face_done[tmp_shared_face_ele_pt])
26000  {
26001  // Get the number of nodes for the current face element
26002  const unsigned tmp_nnodes = tmp_shared_face_ele_pt->nnode();
26003 
26004  // Get each individual node
26005  Node* left_node_pt = tmp_shared_face_ele_pt->node_pt(0);
26006  Node* right_node_pt = tmp_shared_face_ele_pt->node_pt(tmp_nnodes-1);
26007 
26008  if (left_node_pt == first_node_pt)
26009  {
26010  // Push front the new node
26011  sorted_nodes.push_front(right_node_pt);
26012  first_node_pt = right_node_pt;
26013  node_added = true;
26014  }
26015  else if (left_node_pt == last_node_pt)
26016  {
26017  // Push back the new node
26018  sorted_nodes.push_back(right_node_pt);
26019  last_node_pt = right_node_pt;
26020  node_added = true;
26021  }
26022  else if (right_node_pt == first_node_pt)
26023  {
26024  // Push front the new node
26025  sorted_nodes.push_front(left_node_pt);
26026  first_node_pt = left_node_pt;
26027  node_added = true;
26028  }
26029  else if (right_node_pt == last_node_pt)
26030  {
26031  // Push back the new node
26032  sorted_nodes.push_back(left_node_pt);
26033  last_node_pt = left_node_pt;
26034  node_added = true;
26035  }
26036 
26037  if (node_added)
26038  {
26039  // Mark as done only if one of its nodes has been added to
26040  // the list
26041  shared_face_done[tmp_shared_face_ele_pt] = true;
26042  nsorted_face_ele++;
26043 
26044  // Break the for
26045  break;
26046  }
26047 
26048  } // if (!shared_face_done[tmp_shared_face_ele_pt])
26049 
26050  } // for (iface < nnonhalo_face_shared_ele)
26051 
26052  } // while (nsorted_face_ele < nnonhalo_face_shared_ele))
26053 
26054  // Here we can safely delete the face elements, they are no longer
26055  // required
26056 
26057  // First the nonhalo face elements
26058  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
26059  {
26060  delete nonhalo_shared_face_ele_pt[inh];
26061  nonhalo_shared_face_ele_pt[inh] = 0;
26062  } // for (inh < nnonhalo_face_shared_ele)
26063 
26064 #ifdef PARANOID
26065  // ... then the halo face elements
26066  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
26067  {
26068  delete halo_shared_face_ele_pt[ih];
26069  halo_shared_face_ele_pt[ih] = 0;
26070  } // for (inh < nhalo_face_shared_ele)
26071 #endif
26072 
26073  // ------------------------------------------------
26074  // Now copy the nodes to the output container
26075  // ------------------------------------------------
26076  // Get the number of nodes in the container
26077  const unsigned n_nodes = sorted_nodes.size();
26078 
26079  // First resize the container
26080  tmp_segment_nodes.resize(1);
26081  tmp_segment_nodes[0].resize(n_nodes);
26082 
26083  // Counter
26084  unsigned counter = 0;
26085 
26086  // Loop over the list of nodes and copy them in the output container
26087  for (std::list<Node*>::iterator it = sorted_nodes.begin();
26088  it != sorted_nodes.end(); it++)
26089  {
26090  tmp_segment_nodes[0][counter] = (*it);
26091  counter++;
26092  } // Loop over sorted nodes
26093 
26094  }
26095 
26096  //=====start of get_required_elemental_information_load_balance_helper====
26097  /// \short Helper function to get the required elemental information from
26098  /// the element that will be sent to iproc processor.
26099  /// This info. involves the association of the element to a boundary or
26100  /// region.
26101  //========================================================================
26102  template<class ELEMENT>
26105  unsigned& iproc,
26106  Vector<Vector<FiniteElement*> > &f_haloed_ele_pt,
26107  FiniteElement* ele_pt)
26108  {
26109  // Check if the element is associated with the original boundaries
26110  const unsigned nbound = this->initial_shared_boundary_id();
26111 
26112  // Get the number of processors
26113  const unsigned nproc = this->communicator_pt()->nproc();
26114 
26115  // ------------------------------------------------------------------
26116  // Stores the information regarding the boundaries associated to the
26117  // element (it that is the case)
26118  Vector<unsigned> associated_boundaries;
26119  Vector<unsigned> face_index_on_boundary;
26120 
26121  unsigned counter_face_indexes = 0;
26122 
26123  for (unsigned b = 0; b < nbound; b++)
26124  {
26125  // Get the number of elements associated to boundary i
26126  const unsigned nboundary_ele = nboundary_element(b);
26127  for (unsigned e = 0; e < nboundary_ele; e++)
26128  {
26129  if (ele_pt == this->boundary_element_pt(b,e))
26130  {
26131  // Keep track of the boundaries associated to the element
26132  associated_boundaries.push_back(b);
26133  // Get the face index
26134  face_index_on_boundary.push_back(face_index_at_boundary(b,e));
26135  counter_face_indexes++;
26136 #ifdef PARANOID
26137  if (counter_face_indexes > 2)
26138  {
26139  std::stringstream error_message;
26140  error_message
26141  << "A triangular element can not have more than two of its faces "
26142  << "on a boundary!!!\n\n";
26143  throw OomphLibError(error_message.str(),
26144  "RefineableTriangleMesh::get_required_elemental_information_helper()",
26145  OOMPH_EXCEPTION_LOCATION);
26146  }
26147 #else
26148  // Already found 2 face indexes on the same boundary?
26149  if (counter_face_indexes==2) {break;}
26150 #endif // #ifdef PARANOID
26151 
26152  } // if (ele_pt == this->boundary_element_pt(b,e))
26153 
26154  } // (e < nboundary_ele)
26155 
26156  } // (b < nbound)
26157 
26158  // If the element is associated to any boundary then package all the
26159  // relevant info
26160  const unsigned nassociated_boundaries = associated_boundaries.size();
26161  if (nassociated_boundaries > 0)
26162  {
26163  Flat_packed_unsigneds.push_back(1);
26164 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26165  Flat_packed_unsigneds_string.push_back("The element is a boundary element");
26166 #endif
26167  Flat_packed_unsigneds.push_back(nassociated_boundaries);
26168 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26169  std::stringstream junk;
26170  junk << "The elements is associated to " << nassociated_boundaries << " boundaries";
26171  Flat_packed_unsigneds_string.push_back(junk.str());
26172 #endif
26173 
26174  // Package the ids of the associated boundaries and the
26175  // corresponding face index for each boundary (if the element is a
26176  // corner element, it will have two faces associated to the
26177  // boundary)
26178  for (unsigned i = 0; i < nassociated_boundaries; i++)
26179  {
26180  unsigned b = associated_boundaries[i];
26181  Flat_packed_unsigneds.push_back(b);
26182 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26183  std::stringstream junk;
26184  junk << "Element associated to boundary " << b << " of " << nassociated_boundaries << " total associated boundaries";
26185  Flat_packed_unsigneds_string.push_back(junk.str());
26186 #endif
26187  unsigned f = face_index_on_boundary[i];
26188  Flat_packed_unsigneds.push_back(f);
26189 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26190  std::stringstream junk2;
26191  junk2 << "Face index " << f << " for associated boundary " << b;
26192  Flat_packed_unsigneds_string.push_back(junk2.str());
26193 #endif
26194  }
26195 
26196  // If the element is associated to any boundary then we should
26197  // check if the mesh has regions, if that is the case then we need
26198  // to check to which region the boundary element does belong
26199 
26200  // If the mesh has regions we should look for the element
26201  // associated to a boundary and a specified region
26202  Vector<Vector<unsigned> > associated_boundaries_and_regions;
26203  Vector<unsigned> face_index_on_boundary_and_region;
26204 
26205  // Now check for the case when we have regions in the mesh
26206  const unsigned n_regions = this->nregion();
26207  if (n_regions > 1)
26208  {
26209  // Used to count the number of faces associated with
26210  // boundary-regions
26211  unsigned counter_face_indexes_in_regions = 0;
26212  // Loop over the boundaries
26213  for (unsigned b = 0; b < nbound; b++)
26214  {
26215  // Go through each region by getting the region id
26216  for (unsigned i_reg = 0 ; i_reg < n_regions; i_reg++)
26217  {
26218  // Get thre region id associated with the (i_reg)-th region
26219  const unsigned region_id =
26220  static_cast<unsigned>(this->Region_attribute[i_reg]);
26221 
26222  // Loop over all elements associated with the current boundary
26223  // and the i_reg-th region and check if the element is part of
26224  // any region
26225  const unsigned nele_in_region =
26226  this->nboundary_element_in_region(b, region_id);
26227  for (unsigned ee = 0; ee < nele_in_region; ee++)
26228  {
26229  // Check if the boundary-region element is the same as the
26230  // element
26231  if (ele_pt ==
26232  this->boundary_element_in_region_pt(b, region_id, ee))
26233  {
26234  // Storage for the boundary and region associated to the
26235  // element
26236  Vector<unsigned> bound_and_region(2);
26237 
26238  // Keep track of the boundaries associated to the element
26239  bound_and_region[0] = b;
26240  // Keep track of the regions associated to the element
26241  bound_and_region[1] = region_id;
26242  // Add the boundaries and regions in the storage to be
26243  // sent to other processors
26244  associated_boundaries_and_regions.push_back(bound_and_region);
26245  // Get the face index and keep track of it
26246  face_index_on_boundary_and_region.push_back(
26247  this->face_index_at_boundary_in_region(b,region_id,ee));
26248 
26249  // Increase the number of faces of the element associated
26250  // to boundary-regions
26251  counter_face_indexes_in_regions++;
26252 
26253 #ifdef PARANOID
26254  if (counter_face_indexes_in_regions > 2)
26255  {
26256  std::stringstream error_message;
26257  error_message
26258  << "A triangular element can not have more than two of its\n"
26259  << "faces on a boundary!!!\n\n";
26260  throw OomphLibError(error_message.str(),
26261  "RefineableTriangleMesh::get_required_elemental_information_helper()",
26262  OOMPH_EXCEPTION_LOCATION);
26263  } // if (counter_face_indexes_in_regions > 2)
26264 #endif
26265 
26266  } // The element is a boundary-region element
26267 
26268  } // for (ee < nele_in_region)
26269 
26270  } // for (i_reg < n_regions)
26271 
26272  } // for (b < nbound)
26273 
26274  } // if (n_regions > 1)
26275 
26276  // Now package the info. to be sent to other processors
26277  const unsigned nassociated_boundaries_and_regions =
26278  associated_boundaries_and_regions.size();
26279  if (nassociated_boundaries_and_regions > 0)
26280  {
26281  Flat_packed_unsigneds.push_back(1);
26282 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26283  Flat_packed_unsigneds_string.push_back("The element is associated to boundaries and regions");
26284 #endif
26285 
26286  Flat_packed_unsigneds.push_back(nassociated_boundaries_and_regions);
26287 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26288  std::stringstream junk;
26289  junk << "The element is associated to " << nassociated_boundaries_and_regions << " boundaries-regions";
26290  Flat_packed_unsigneds_string.push_back(junk.str());
26291 #endif
26292 
26293  // Package the ids of the associated boundaries, regions and the
26294  // corresponding face index for each boundary-region (if the
26295  // element is a corner element, it will have two faces
26296  // associated to the boundary-region)
26297  for (unsigned i = 0; i < nassociated_boundaries_and_regions; i++)
26298  {
26299  const unsigned b = associated_boundaries_and_regions[i][0];
26300  Flat_packed_unsigneds.push_back(b);
26301 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26302  std::stringstream junk;
26303  junk << "Element associated to boundary " << b << " of " << nassociated_boundaries_and_regions << " total associated boundaries-regions";
26304  Flat_packed_unsigneds_string.push_back(junk.str());
26305 #endif
26306 
26307  const unsigned r = associated_boundaries_and_regions[i][1];
26308  Flat_packed_unsigneds.push_back(r);
26309 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26310  std::stringstream junk2;
26311  junk2 << "Element associated to region " << r << " of " << nassociated_boundaries_and_regions << " total associated boundaries-regions";
26312  Flat_packed_unsigneds_string.push_back(junk2.str());
26313 #endif
26314 
26315  const unsigned f = face_index_on_boundary_and_region[i];
26316  Flat_packed_unsigneds.push_back(f);
26317 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26318  std::stringstream junk3;
26319  junk3 << "Face index " << f << " for associated boundary-region (" << b << "-" << r << ")";
26320  Flat_packed_unsigneds_string.push_back(junk3.str());
26321 #endif
26322  } // for (i < nassociated_boundaries_and_regions)
26323  } // if (nassociated_boundaries_and_regions > 0)
26324  else
26325  {
26326  Flat_packed_unsigneds.push_back(0);
26327 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26328  Flat_packed_unsigneds_string.push_back("The element is NOT associated to boundaries and regions");
26329 #endif
26330  } // else if (nassociated_boundaries_and_regions > 0)
26331 
26332  }
26333  else
26334  {
26335  Flat_packed_unsigneds.push_back(0);
26336 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26337  Flat_packed_unsigneds_string.push_back("The element is not associated to any original boundary");
26338 #endif
26339  }
26340 
26341  // ------------------------------------------------------------
26342  // Now review if the element is associated to a shared boundary
26343 
26344  // Store the shared boundaries, and therefore the face indexes
26345  // associated to the element
26346  Vector<unsigned> associated_shared_boundaries;
26347  Vector<unsigned> face_index_on_shared_boundary;
26348 
26349  // Get the shared boundaries in this processor
26350  Vector<unsigned> my_rank_shared_boundaries_ids;
26351  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
26352 
26353  // Get the number of shared boundaries
26354  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
26355  // Loop over the shared boundaries
26356  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
26357  {
26358  // Get the boundary id
26359  const unsigned sb = my_rank_shared_boundaries_ids[i];
26360 
26361  // Get the number of elements associated to shared boundary sb
26362  const unsigned nboundary_ele = this->nshared_boundary_element(sb);
26363  for (unsigned e = 0; e < nboundary_ele; e++)
26364  {
26365  if (ele_pt == this->shared_boundary_element_pt(sb,e))
26366  {
26367  // Keep track of the boundaries associated to the element
26368  associated_shared_boundaries.push_back(sb);
26369  // Get the face index
26370  face_index_on_shared_boundary.push_back(
26371  this->face_index_at_shared_boundary(sb, e));
26372  }
26373  } // (e < nboundary_ele)
26374  } // (i < nmy_rank_shd_bnd)
26375 
26376  // If the element is associated to a shared boundary then package
26377  // all the relevant info
26378  const unsigned nassociated_shared_boundaries =
26379  associated_shared_boundaries.size();
26380  if (nassociated_shared_boundaries > 0)
26381  {
26382  Flat_packed_unsigneds.push_back(3);
26383 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26384  Flat_packed_unsigneds_string.push_back("The element is a shared boundary element");
26385 #endif
26386  Flat_packed_unsigneds.push_back(nassociated_shared_boundaries);
26387 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26388  std::stringstream junk;
26389  junk << "The elements is associated to " << nassociated_shared_boundaries << "shared boundaries";
26390  Flat_packed_unsigneds_string.push_back(junk.str());
26391 #endif
26392 
26393  // Package the ids of the associated boundaries
26394  for (unsigned i = 0; i < nassociated_shared_boundaries; i++)
26395  {
26396  const unsigned b = associated_shared_boundaries[i];
26397  Flat_packed_unsigneds.push_back(b);
26398 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26399  std::stringstream junk;
26400  junk << "Element associated to shared boundary " << b << " of " << nassociated_shared_boundaries << " total associated boundaries";
26401  Flat_packed_unsigneds_string.push_back(junk.str());
26402 #endif
26403 
26404  const unsigned f = face_index_on_shared_boundary[i];
26405  Flat_packed_unsigneds.push_back(f);
26406 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26407  std::stringstream junk2;
26408  junk2 << "Face index " << f << " for associated shared boundary " << b;
26409  Flat_packed_unsigneds_string.push_back(junk2.str());
26410 #endif
26411  }
26412  }
26413  else
26414  {
26415  Flat_packed_unsigneds.push_back(0);
26416 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26417  Flat_packed_unsigneds_string.push_back("The element is not associated to any shared boundary");
26418 #endif
26419  }
26420 
26421  // Now check if the element is haloed with any processor
26422 
26423  // Store the index of the haloed element with the jproc
26424  Vector<Vector<unsigned> > index_haloed(nproc);
26425 
26426  // Loop over the processors
26427  for (unsigned jproc = 0; jproc < nproc; jproc++)
26428  {
26429  // Get the number of haloed elements with jproc
26430  const unsigned n_haloed_jproc = f_haloed_ele_pt[jproc].size();
26431  // Loop over the haloed elements with jproc
26432  for (unsigned ihd =0; ihd < n_haloed_jproc; ihd++)
26433  {
26434  // Is a haloed element?
26435  if (ele_pt == f_haloed_ele_pt[jproc][ihd])
26436  {
26437  // Store the haloed index with the jproc processor
26438  index_haloed[jproc].push_back(ihd);
26439  // Break the searching with the jproc processor
26440  break;
26441  } // if (ele_pt == f_haloed_ele_pt[jproc][ihd])
26442 
26443  } // for (ihd < n_haloed_jproc)
26444 
26445  } // for (jproc < nproc)
26446 
26447  // Send the haloed info.
26448  // Loop over the processors
26449  for (unsigned jproc = 0; jproc < nproc; jproc++)
26450  {
26451  // Is the element haloed with the jproc processor
26452  const unsigned n_index_haloed_jproc = index_haloed[jproc].size();
26453  Flat_packed_unsigneds.push_back(n_index_haloed_jproc);
26454 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26455  Flat_packed_unsigneds_string.push_back("The number of haloed indexes the element is with processor jproc");
26456 #endif
26457  for (unsigned ihd = 0; ihd < n_index_haloed_jproc; ihd++)
26458  {
26459  Flat_packed_unsigneds.push_back(index_haloed[jproc][ihd]);
26460 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26461  Flat_packed_unsigneds_string.push_back("The haloed index of the element with jproc");
26462 #endif
26463  } // for (ihd < n_index_haloed_jproc)
26464 
26465  } // for (jproc < nproc)
26466 
26467  }
26468 
26469  //======================================================================
26470  /// \short Helper function to add nodes on a new domain as a result of
26471  /// load balance
26472  //======================================================================
26473  template <class ELEMENT>
26476  Vector<Vector<FiniteElement*> >&f_halo_ele_pt,
26477  Vector<Node*> &new_nodes_on_domain,
26478  Node* nod_pt)
26479  {
26480  // Attempt to add this node to the new domain
26481  const unsigned nnew_nodes_on_domain= new_nodes_on_domain.size();
26482  const unsigned new_added_node_index =
26483  this->try_to_add_node_pt_load_balance(new_nodes_on_domain, nod_pt);
26484 
26485  // If it was added then the new index should match the size of the storage
26486  if (new_added_node_index == nnew_nodes_on_domain)
26487  {
26488  Flat_packed_unsigneds.push_back(1);
26489 
26490 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26491  std::stringstream junk;
26492  junk << "Node needs to be constructed [size="
26493  << Flat_packed_unsigneds.size() << "]; last entry: "
26495  Flat_packed_unsigneds_string.push_back(junk.str());
26496 #endif
26497 
26498  // This helper function gets all the required information for the
26499  // specified node and stores it into MPI-sendable information
26500  // so that a new copy can be made on the receiving process
26501  get_required_nodal_information_load_balance_helper(f_halo_ele_pt,
26502  iproc,
26503  nod_pt);
26504  }
26505  else // It was already added
26506  {
26507  Flat_packed_unsigneds.push_back(0);
26508 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26509  std::stringstream junk;
26510  junk << "Node was already added [size="
26511  << Flat_packed_unsigneds.size() << "]; last entry: "
26513 
26514  Flat_packed_unsigneds_string.push_back(junk.str());
26515 #endif
26516 
26517  // This node has been already added, so tell the other process
26518  // its index in the equivalent storage
26519  Flat_packed_unsigneds.push_back(new_added_node_index);
26520 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26521  Flat_packed_unsigneds_string.push_back("new added node index");
26522 #endif
26523  }
26524 
26525  }
26526 
26527  //======start of get_required_nodal_information_load_balance_helper=======
26528  /// Helper function to get the required nodal information from an
26529  /// haloed node so that a fully-functional halo node (and therefore element)
26530  /// can be created on the receiving process
26531  //========================================================================
26532  template<class ELEMENT>
26535  Vector<Vector<FiniteElement*> > &f_halo_ele_pt,
26536  unsigned& iproc,
26537  Node* nod_pt)
26538  {
26539  unsigned my_rank = this->communicator_pt()->my_rank();
26540  const unsigned nproc = this->communicator_pt()->nproc();
26541 
26542  // Tell the halo copy of this node how many values there are
26543  // [NB this may be different for nodes within the same element, e.g.
26544  // when using Lagrange multipliers]
26545  unsigned n_val=nod_pt->nvalue();
26546  Flat_packed_unsigneds.push_back(n_val);
26547 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26548  Flat_packed_unsigneds_string.push_back("Number of values");
26549 #endif
26550 
26551  unsigned n_dim=nod_pt->ndim();
26552 
26553  // Default number of previous values to 1
26554  unsigned n_prev=1;
26555  if (this->Time_stepper_pt!=0)
26556  {
26557  // Add number of history values to n_prev
26558  n_prev=this->Time_stepper_pt->ntstorage();
26559  }
26560 
26561  // -----------------------------------------------------
26562  // Is the node on an original boundary?
26563  // Store the original boundaries where the node may be
26564  Vector<unsigned> original_boundaries;
26565  // Loop over the original boundaries of the mesh and check if live
26566  // on one of them
26567  const unsigned n_bnd = this->initial_shared_boundary_id();
26568  for (unsigned bb=0;bb<n_bnd;bb++)
26569  {
26570  // Which boundaries (could be more than one) is it on?
26571  if (nod_pt->is_on_boundary(bb))
26572  {
26573  original_boundaries.push_back(bb);
26574  }
26575 
26576  }
26577 
26578  const unsigned n_original_boundaries = original_boundaries.size();
26579  // Is the node on any original boundary?
26580  if (n_original_boundaries > 0)
26581  {
26582  // Indicate that the node is on an original boundary
26583  Flat_packed_unsigneds.push_back(2);
26584 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26585  Flat_packed_unsigneds_string.push_back("Node is on the original boundaries");
26586 #endif
26587 
26588  Flat_packed_unsigneds.push_back(n_original_boundaries);
26589 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26590  std::stringstream junk;
26591  junk << "Node is on "<< n_original_boundaries << " original boundaries";
26592  Flat_packed_unsigneds_string.push_back(junk.str());
26593 #endif
26594 
26595  // Loop over the original boundaries the node is on
26596  for (unsigned i=0;i<n_original_boundaries;i++)
26597  {
26598  Flat_packed_unsigneds.push_back(original_boundaries[i]);
26599 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26600  std::stringstream junk;
26601  junk<<"Node is on boundary "<<original_boundaries[i]<<" of "<< nb;
26602  Flat_packed_unsigneds_string.push_back(junk.str());
26603 #endif
26604  // Get the boundary coordinate of the node
26605  Vector<double> zeta(1);
26606  nod_pt->get_coordinates_on_boundary(original_boundaries[i],zeta);
26607  Flat_packed_doubles.push_back(zeta[0]);
26608  }
26609  }
26610  else
26611  {
26612  // Indicate that the node is NOT on an original boundary
26613  Flat_packed_unsigneds.push_back(0);
26614 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26615  Flat_packed_unsigneds_string.push_back("Node is on any original boundary");
26616 #endif
26617  }
26618 
26619  // -------------------------------------------------------
26620  // Is the node on shared boundaries?
26621  bool node_on_shared_boundary = false;
26622  // Loop over the shared boundaries with the iproc processors and
26623  // check if live on one of them
26624  const unsigned n_shd_bnd = this->nshared_boundaries(my_rank, iproc);
26625  for (unsigned bb=0;bb<n_shd_bnd;bb++)
26626  {
26627  // Get the boundary id
26628  unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
26629  // Which boundaries (could be more than one) is it on?
26630  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
26631  {
26632  node_on_shared_boundary = true;
26633  break;
26634  }
26635  }
26636 
26637  // If the node live on any of the shared boundaries with the iproc
26638  // processor then just get the node number according to the
26639  // sorted_shared_boundary_node_pt() scheme and send it accross
26640  if (node_on_shared_boundary)
26641  {
26642  Flat_packed_unsigneds.push_back(1);
26643 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26644  Flat_packed_unsigneds_string.push_back("Node is on shared boundary");
26645 #endif
26646 
26647  // Store the shared boundaries where the node is on
26648  Vector<unsigned> shd_boundaries;
26649  // Loop over the shared boundaries with the iproc processor
26650  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
26651  {
26652  // Get the boundary id
26653  const unsigned i_bnd =
26654  this->shared_boundaries_ids(my_rank, iproc, bb);
26655  // Which boundaries (could be more than one) is it on?
26656  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
26657  {
26658  shd_boundaries.push_back(i_bnd);
26659  }
26660  }
26661 
26662  // Get the number of shared boundaries the node is on
26663  const unsigned n_shd_bnd_is_on = shd_boundaries.size();
26664  // Send the number of shared boundaries the node is on
26665  Flat_packed_unsigneds.push_back(n_shd_bnd_is_on);
26666 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26667  std::stringstream junk;
26668  junk << "Node is on "<< n_shd_bnd_is_on << " shared boundaries";
26669  Flat_packed_unsigneds_string.push_back(junk.str());
26670 #endif
26671 
26672  // Loop over the shared boundaries to send their ids
26673  for (unsigned i=0;i<n_shd_bnd_is_on;i++)
26674  {
26675  Flat_packed_unsigneds.push_back(shd_boundaries[i]);
26676 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26677  std::stringstream junk;
26678  junk << "Node is on boundary " << shd_boundaries[i] << " of " << nb;
26679  Flat_packed_unsigneds_string.push_back(junk.str());
26680 #endif
26681  }
26682 
26683  // Given that the node is on at least one boundary get the index
26684  // of the node in one of the boundaries and send this index
26685  unsigned shared_boundary_id = shd_boundaries[0];
26686  // Get the number of nodes on the given shared boundary
26687  const unsigned n_nodes_on_shared_boundary =
26688  nsorted_shared_boundary_node(shared_boundary_id);
26689  // Store the index of the node on the shared boundary
26690  unsigned index_node_on_shared_boundary;
26691 #ifdef PARANOID
26692  // Flag to know if the node has been found
26693  bool found_index_node_on_shared_boundary = false;
26694 #endif
26695  // Loop over the nodes on the shared boundary to find the node
26696  for (unsigned i = 0; i < n_nodes_on_shared_boundary; i++)
26697  {
26698  // Get the i-th node on the shared boundary
26699  Node* shared_node_pt =
26700  sorted_shared_boundary_node_pt(shared_boundary_id, i);
26701  // Is the node we are looking for
26702  if (shared_node_pt == nod_pt)
26703  {
26704  // Store the index
26705  index_node_on_shared_boundary = i;
26706 #ifdef PARANOID
26707  // Mark as found
26708  found_index_node_on_shared_boundary = true;
26709 #endif
26710  break; // break
26711  }
26712 
26713  } // for (i < nnodes_on_shared_boundary)
26714 
26715 #ifdef PARANOID
26716  if (!found_index_node_on_shared_boundary)
26717  {
26718  std::ostringstream error_message;
26719  error_message
26720  <<"The index of the node on boundary ("
26721  <<shared_boundary_id<<") was not found.\n"
26722  <<"The node coordinates are ("<<nod_pt->x(0)<<","
26723  <<nod_pt->x(1)<<").\n";
26724  throw OomphLibError(
26725  error_message.str(),
26726  "RefineableTriangleMesh::get_required_nodal_information_helper()",
26727  OOMPH_EXCEPTION_LOCATION);
26728  }
26729 #endif
26730  // Send the index of the node on the shared boundary
26731  Flat_packed_unsigneds.push_back(index_node_on_shared_boundary);
26732 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26733  std::stringstream junk2;
26734  junk2 << "Node index on boundary "<<boundaries[0]<<" is "
26735  <<index_node_on_shared_boundary;
26736  Flat_packed_unsigneds_string.push_back(junk2.str());
26737 #endif
26738 
26739  } // if (node_on_shared_boundary)
26740  else
26741  {
26742  // The node is not on a shared boundary
26743  Flat_packed_unsigneds.push_back(0);
26744 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26745  Flat_packed_unsigneds_string.push_back("Node is not on a shared boundary");
26746 #endif
26747  }
26748 
26749  // ----------------------------------------------------------------
26750  // Is the node on any shared boundary where the receiver processor
26751  // is not involved?
26752 
26753  // Now check if the node is on a shared boundary created by the
26754  // current processor (my_rank) and other processor different that
26755  // the iproc processor. This info. will help to complete the sending
26756  // of halo(ed) information between processors
26757 
26758  // Flag to know if the node is on a shared boundary with other
26759  // processor
26760  bool node_on_shared_boundary_with_other_processors = false;
26761  // Count the number of other shared boundaries it could be on
26762  unsigned nshared_boundaries_with_other_processors_have_node = 0;
26763 
26764  // Loop over the shared boundaries of the sent processor (my_rank)
26765  // and other processors (jproc)
26766  for (unsigned jproc = 0; jproc < nproc; jproc++)
26767  {
26768  // Do not search with the iproc processor, that was done before
26769  // above
26770  if (jproc != iproc)
26771  {
26772  // Get the number of shared boundaries with the jproc processor
26773  const unsigned n_jshd_bnd =
26774  this->nshared_boundaries(my_rank, jproc);
26775  // Loop over the shared boundaries
26776  for (unsigned bb=0;bb<n_jshd_bnd;bb++)
26777  {
26778  // Get the boundary id
26779  const unsigned j_shd_bnd =
26780  this->shared_boundaries_ids(my_rank, jproc, bb);
26781  // Is the node part of this boundary?
26782  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
26783  {
26784 // DEBP("Sending to");
26785 // DEBP(iproc);
26786 // DEBP("Pair of procs where other shared");
26787 // DEBP(my_rank);
26788 // DEBP(jproc);
26789 // DEBP(i_bnd);
26790  node_on_shared_boundary_with_other_processors = true;
26791  // Increase the counter for the number of shared boundaries
26792  // with other processors the node is on
26793  nshared_boundaries_with_other_processors_have_node++;
26794  } // if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt)
26795 
26796  } // for (bb<n_jshd_bnd)
26797 
26798  } // if (jproc != iproc)
26799 
26800  } // for (jproc < nproc)
26801 
26802  // If the node is on a shared boundary with another processor
26803  // (my_rank, jproc), then send the flag and look for the info.
26804  if (node_on_shared_boundary_with_other_processors)
26805  {
26806  Flat_packed_unsigneds.push_back(4);
26807 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26808  Flat_packed_unsigneds_string.push_back("Node is on shared boundary no related with the received processor: 4");
26809 #endif
26810 
26811  // The number of packages of information that will be sent to the
26812  // "iproc" processor. This helps to know how many packages of data
26813  // read from the received processor
26814  Flat_packed_unsigneds.push_back(nshared_boundaries_with_other_processors_have_node);
26815 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26816  std::stringstream junk;
26817  junk << "Number of other shared boundaries that the node is on: "
26818  << nshared_boundaries_with_other_processors_have_node;
26819  Flat_packed_unsigneds_string.push_back(junk.str());
26820 #endif
26821 
26822  // Counter to ensure that the correct number of data has been sent
26823  unsigned counter_shd_bnd_with_other_procs_have_node = 0;
26824  // Loop over the shared boundaries with other processors and get:
26825  // 1) The processors defining the shared boundary
26826  // 2) The shared boundary id
26827  // 3) The index of the node on the shared boundary
26828  Vector<unsigned> other_processor_1;
26829  Vector<unsigned> other_processor_2;
26830  Vector<unsigned> shd_bnd_ids;
26831  Vector<unsigned> indexes;
26832  // Loop over the processors again
26833  for (unsigned jproc = 0; jproc < nproc; jproc++)
26834  {
26835  // Do not search with the iproc processor, that was done before
26836  // above
26837  if (jproc != iproc)
26838  {
26839  // Get the number of shared boundaries with the jproc
26840  // processor
26841  const unsigned n_jshd_bnd =
26842  this->nshared_boundaries(my_rank, jproc);
26843  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
26844  {
26845  // Get the boundary id
26846  const unsigned j_shd_bnd =
26847  this->shared_boundaries_ids(my_rank, jproc, bb);
26848  // Is the node part of this boundary?
26849  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
26850  {
26851  // Include the first processor
26852  other_processor_1.push_back(my_rank);
26853  // Include the second processor
26854  other_processor_2.push_back(jproc);
26855  // Include the shared boundary id
26856  shd_bnd_ids.push_back(j_shd_bnd);
26857  // Increase the counter for found shared boundaries with
26858  // other processors
26859  counter_shd_bnd_with_other_procs_have_node++;
26860  }
26861 
26862  } // for (bb < nshared_bnd)
26863 
26864  } // if (jproc != iproc)
26865 
26866  } // for (jproc < nproc)
26867 
26868  // Get the indexes of the node on all the shared boundaries where
26869  // it was found
26870  const unsigned n_other_processors = other_processor_1.size();
26871  // Loop over the processors where the node was found
26872  for (unsigned i = 0; i < n_other_processors; i++)
26873  {
26874  // Get the shared boundary id
26875  unsigned shd_bnd_id = shd_bnd_ids[i];
26876  // Get the number of nodes on that shared boundary
26877  const unsigned n_nodes_on_shd_bnd =
26878  nsorted_shared_boundary_node(shd_bnd_id);
26879 
26880 #ifdef PARANOID
26881  bool found_index_node_on_shared_boundary = false;
26882 #endif
26883  for (unsigned i = 0; i < n_nodes_on_shd_bnd; i++)
26884  {
26885  // Get the i-th shared boundary node
26886  Node* shared_node_pt =
26887  sorted_shared_boundary_node_pt(shd_bnd_id, i);
26888  // Is the same node?
26889  if (shared_node_pt == nod_pt)
26890  {
26891 // DEBP(i_node);
26892 // DEBP(nod_pt->x(0));
26893 // DEBP(nod_pt->x(1));
26894  // Include the index of the node
26895  indexes.push_back(i);
26896 #ifdef PARANOID
26897  // Mark as found the node
26898  found_index_node_on_shared_boundary = true;
26899 #endif
26900  break;
26901  } // if (shared_node_pt == nod_pt)
26902 
26903  } // for (i < n_nodes_on_shd_bnd)
26904 
26905 #ifdef PARANOID
26906  if (!found_index_node_on_shared_boundary)
26907  {
26908  std::ostringstream error_message;
26909  error_message
26910  <<"The index of the node on boundary ("
26911  <<shd_bnd_id<<"), shared by other processors\nwas not found.\n"
26912  <<"The node coordinates are ("<<nod_pt->x(0)<<","
26913  <<nod_pt->x(1)<<").\n";
26914  throw OomphLibError(
26915  error_message.str(),
26916  "RefineableTriangleMesh::get_required_nodal_information_helper()",
26917  OOMPH_EXCEPTION_LOCATION);
26918  }
26919 #endif
26920  } // for (i < n_other_processors)
26921 
26922  // Now send the info. but first check that the number of found
26923  // nodes be the same that the previously found shared boundaries
26924  // with the node
26925 #ifdef PARANOID
26926  if (counter_shd_bnd_with_other_procs_have_node !=
26927  nshared_boundaries_with_other_processors_have_node)
26928  {
26929  std::ostringstream error_message;
26930  error_message
26931  <<"The number of shared boundaries where the node is on "
26932  <<"is different:\n"
26933  << "nshared_boundaries_with_other_processors_have_node: ("
26934  << nshared_boundaries_with_other_processors_have_node
26935  << ")\n"
26936  << "counter_shd_bnd_with_other_procs_have_node: ("
26937  << counter_shd_bnd_with_other_procs_have_node
26938  << ")\n";
26939  throw OomphLibError(
26940  error_message.str(),
26941  "RefineableTriangleMesh::get_required_nodal_information_helper()",
26942  OOMPH_EXCEPTION_LOCATION);
26943  } // if (counter_shd_bnd_with_other_procs_have_node !=
26944  // nshared_boundaries_with_other_processors_have_node)
26945 #endif
26946 
26947  // Loop over the info. to send it
26948  for (unsigned i = 0; i < n_other_processors; i++)
26949  {
26950  Flat_packed_unsigneds.push_back(other_processor_1[i]);
26951 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26952  std::stringstream junk1;
26953  junk1 << "Processor where the other shared boundary "
26954  << "has the node: " << other_processor_1[i];
26955  Flat_packed_unsigneds_string.push_back(junk1.str());
26956 #endif
26957 
26958  Flat_packed_unsigneds.push_back(other_processor_2[i]);
26959 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26960  std::stringstream junk2;
26961  junk2 << "Processor where the other shared boundary "
26962  << "has the node: " << other_processor_2[i];
26963  Flat_packed_unsigneds_string.push_back(junk2.str());
26964 #endif
26965 
26966  Flat_packed_unsigneds.push_back(shd_bnd_ids[i]);
26967 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26968  std::stringstream junk3;
26969  junk3 << "Other shared boundary id where the node is on"
26970  << boundaries[i];
26971  Flat_packed_unsigneds_string.push_back(junk3.str());
26972 #endif
26973 
26974  Flat_packed_unsigneds.push_back(indexes[i]);
26975 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26976  std::stringstream junk4;
26977  junk4 << "Node index on other shared boundary "
26978  <<boundaries[i] << " is "
26979  << indexes[i];
26980  Flat_packed_unsigneds_string.push_back(junk4.str());
26981 #endif
26982 
26983  } // for (i < n_other_processors)
26984 
26985  } // if (node_on_shared_boundary_with_other_processors)
26986  else
26987  {
26988  Flat_packed_unsigneds.push_back(0);
26989 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26990  Flat_packed_unsigneds_string.push_back("Node is on any shared boundary with other processors");
26991 #endif
26992  } // else if (node_on_shared_boundary_with_other_processors)
26993 
26994  // It may still be possible that the node be shared with the
26995  // processor that receives the info. but it is neither on shared
26996  // boundary with the receiver processor nor on a shared boundary
26997  // with others processors. Think in the next case:
26998 
26999  // |-----|-----| - The elements in processor 3 need to be sent to
27000  // | 4 | 3 | processor 1, and that is all
27001  // |-----*-----| - When processor 1 receives the data from node (*)
27002  // | 1 | 2 | it just RE-CREATES it becasuse it is does not know
27003  // |-----|-----| that the node is also on the shared boundary that
27004  // processor 1 and 2 or processor 1 and 4 share.
27005 
27006  // This problem become even worse if there would be more processors
27007  // between processor 3 and 2, or/and processor 3 and 4. Think in
27008  // triangles sharing the node (*)
27009 
27010  // To solve this check if the node that we are trying to send is
27011  // part of the halo elements of the curreent processor (my_rank)
27012  // with any other processor (we need to check with all the
27013  // processors and not just with the processors to which we will send
27014  // to cover more cases)
27015 
27016  // Store the halo element number with jproc where the node was found
27017  Vector<Vector<unsigned> > halo_element_number(nproc);
27018  // Store the node number on the halo element where the node was found
27019  Vector<Vector<unsigned> > halo_node_number_in_halo_element(nproc);
27020 
27021  // Loop over the processor
27022  for (unsigned jproc = 0; jproc < nproc; jproc++)
27023  {
27024  // Get the number of halo elements with the jproc processor
27025  const unsigned n_halo_jproc = f_halo_ele_pt[jproc].size();
27026  // Loop over the halo elements
27027  for (unsigned jh = 0; jh < n_halo_jproc; jh++)
27028  {
27029  FiniteElement* halo_ele_pt = f_halo_ele_pt[jproc][jh];
27030  // Get the number of nodes of the halo element
27031  const unsigned n_node = halo_ele_pt->nnode();
27032  // Loop over the nodes
27033  for (unsigned n = 0; n < n_node; n++)
27034  {
27035  // Is the node part of the ih-th halo element with jproc
27036  if (nod_pt == halo_ele_pt->node_pt(n))
27037  {
27038  halo_element_number[jproc].push_back(jh);
27039  halo_node_number_in_halo_element[jproc].push_back(n);
27040  // break with the nodes, no need to look for more nodes in
27041  // the element
27042  break;
27043  } // if (nod_pt == halo_ele_pt->node_pt(n))
27044 
27045  } // for (n < n_node)
27046 
27047  } // for (jh < n_halo_jproc)
27048 
27049  } // for (jproc < nproc)
27050 
27051  // Send the info. related with if the node is on halo elements with
27052  // any processor
27053 
27054  // Loop over the processors
27055  for (unsigned jproc = 0; jproc < nproc; jproc++)
27056  {
27057  // Get the number of halo elements with jproc processor where the
27058  // node is
27059  const unsigned n_jproc_halo_ele_node_is_on =
27060  halo_element_number[jproc].size();
27061  // Send the number of halo elements with jproc where the node is
27062  Flat_packed_unsigneds.push_back(n_jproc_halo_ele_node_is_on);
27063 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27064  std::stringstream junk5;
27065  junk5 << "Node is on " << n_jproc_halo_ele_node_is_on << " halo "
27066  << "elements with " << jproc << "-th processor";
27067  Flat_packed_unsigneds_string.push_back(junk5.str());
27068 #endif
27069  // Send the halo elements indexes (which will be haloed elements
27070  // indexes in the receiver processor), and the indexes of the
27071  // nodes in each halo element
27072  for (unsigned i = 0; i < n_jproc_halo_ele_node_is_on; i++)
27073  {
27074  // The halo element index
27075  const unsigned halo_element_index = halo_element_number[jproc][i];
27076  Flat_packed_unsigneds.push_back(halo_element_index);
27077 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27078  std::stringstream junk6;
27079  junk6 << "Halo element index is ("<<halo_element_index
27080  <<") with processor ("<<jproc<<")";
27081  Flat_packed_unsigneds_string.push_back(junk6.str());
27082 #endif
27083  // The node index on the halo element
27084  const unsigned node_index = halo_node_number_in_halo_element[jproc][i];
27085  Flat_packed_unsigneds.push_back(node_index);
27086 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27087  std::stringstream junk7;
27088  junk7 << "The node index on the halo element index is ("
27089  << node_index;
27090  Flat_packed_unsigneds_string.push_back(junk7.str());
27091 #endif
27092 
27093  } // for (i < n_jproc_halo_ele_node_is_on)
27094 
27095  } // for (jproc < nproc)
27096 
27097  // Now check if it is required to send the info. of the node. If the
27098  // node is not on a shared boundary with the iproc processor then we
27099  // need to send the info.
27100 
27101  // Flag to indicate if it is on a halo element with the iproc
27102  // processor. If this flag is true then there is no need to send the
27103  // info. to create the node, in the receiver processor the info is
27104  // copied from the indicated haloed element-node
27105  bool on_halo_element_with_iproc_processor = false;
27106  if (halo_element_number[iproc].size() > 0)
27107  {
27108  on_halo_element_with_iproc_processor = true;
27109  } // if (halo_element_number[iproc].size() > 0)
27110 
27111  // if (!node_on_shared_boundary)
27112  if (!node_on_shared_boundary && !on_halo_element_with_iproc_processor)
27113  {
27114  // Send all the info. to create it
27115 
27116  // Is the Node algebraic? If so, send its ref values and
27117  // an indication of its geometric objects if they are stored
27118  // in the algebraic mesh
27119  AlgebraicNode* alg_nod_pt=dynamic_cast<AlgebraicNode*>(nod_pt);
27120  if (alg_nod_pt!=0)
27121  {
27122  // The external mesh should be algebraic
27123  AlgebraicMesh* alg_mesh_pt=dynamic_cast<AlgebraicMesh*>(this);
27124 
27125  // Get default node update function ID
27126  unsigned update_id=alg_nod_pt->node_update_fct_id();
27127  Flat_packed_unsigneds.push_back(update_id);
27128 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27129  Flat_packed_unsigneds_string.push_back("Alg Node update id");
27130 #endif
27131 
27132  // Get reference values at default...
27133  unsigned n_ref_val=alg_nod_pt->nref_value();
27134  Flat_packed_unsigneds.push_back(n_ref_val);
27135 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27136  Flat_packed_unsigneds_string.push_back("Alg Node n ref values");
27137 #endif
27138  for (unsigned i_ref_val=0;i_ref_val<n_ref_val;i_ref_val++)
27139  {
27140  Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
27141  }
27142 
27143  // Access geometric objects at default...
27144  unsigned n_geom_obj=alg_nod_pt->ngeom_object();
27145  Flat_packed_unsigneds.push_back(n_geom_obj);
27146 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27147  Flat_packed_unsigneds_string.push_back("Alg Node n geom objects");
27148 #endif
27149  for (unsigned i_geom=0;i_geom<n_geom_obj;i_geom++)
27150  {
27151  GeomObject* geom_obj_pt=alg_nod_pt->geom_object_pt(i_geom);
27152 
27153  // Check this against the stored geometric objects in mesh
27154  unsigned n_geom_list=alg_mesh_pt->ngeom_object_list_pt();
27155 
27156  // Default found index to zero
27157  unsigned found_geom_object=0;
27158  for (unsigned i_list=0;i_list<n_geom_list;i_list++)
27159  {
27160  if (geom_obj_pt==alg_mesh_pt->geom_object_list_pt(i_list))
27161  {
27162  found_geom_object=i_list;
27163  }
27164  }
27165  Flat_packed_unsigneds.push_back(found_geom_object);
27166 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27167  Flat_packed_unsigneds_string.push_back("Found geom object");
27168 #endif
27169  }
27170  } // (if alg_nod_pt!=0)
27171 
27172  // Is it a SolidNode?
27173  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(nod_pt);
27174  if (solid_nod_pt!=0)
27175  {
27176  unsigned n_solid_val=solid_nod_pt->variable_position_pt()->nvalue();
27177  for (unsigned i_val=0;i_val<n_solid_val;i_val++)
27178  {
27179  for (unsigned t=0;t<n_prev;t++)
27180  {
27181  Flat_packed_doubles.push_back(solid_nod_pt->variable_position_pt()->
27182  value(t,i_val));
27183  }
27184  }
27185 
27186  Vector<double> values_solid_node;
27187  solid_nod_pt->add_values_to_vector(values_solid_node);
27188  const unsigned nvalues_solid_node = values_solid_node.size();
27189  Flat_packed_unsigneds.push_back(nvalues_solid_node);
27190 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27191  std::stringstream junk;
27192  junk << "Number of values solid node: "
27193  << nvalues_solid_node;
27194  Flat_packed_unsigneds_string.push_back(junk.str());
27195 #endif
27196  for (unsigned i = 0; i < nvalues_solid_node; i++)
27197  {
27198  Flat_packed_doubles.push_back(values_solid_node[i]);
27199  }
27200  }
27201 
27202  // Finally copy info required for all node types
27203  for (unsigned i_val=0;i_val<n_val;i_val++)
27204  {
27205  for (unsigned t=0;t<n_prev;t++)
27206  {
27207  Flat_packed_doubles.push_back(nod_pt->value(t,i_val));
27208  }
27209  }
27210 
27211  // Now do positions
27212  for (unsigned idim=0;idim<n_dim;idim++)
27213  {
27214  for (unsigned t=0;t<n_prev;t++)
27215  {
27216  Flat_packed_doubles.push_back(nod_pt->x(t,idim));
27217 // DEBP(nod_pt->x(t,idim));
27218  }
27219  }
27220 
27221  } // if (!node_on_shared_boundary && !on_halo_element_with_iproc_processor)
27222 
27223  }
27224 
27225  //======================================================================
27226  /// \short Helper function to create elements on the loop
27227  /// process based on the info received in
27228  /// send_and_received_elements_nodes_info
27229  //======================================================================
27230  template <class ELEMENT>
27232  unsigned& iproc,
27233  Vector<Vector<FiniteElement*> > &f_haloed_ele_pt,
27234  Vector<Vector<std::map<unsigned,FiniteElement*> > >
27235  &received_old_haloed_element_pt,
27236  Vector<FiniteElement*> &new_elements_on_domain,
27237  Vector<Node*> &new_nodes_on_domain,
27238  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
27239  &other_proc_shd_bnd_node_pt,
27240  Vector<Vector<Vector<unsigned> > > &global_node_names,
27241  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
27242  Vector<Node*> &global_shared_node_pt)
27243  {
27244 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27246  << " Bool: New element needs to be constructed "
27248  << std::endl;
27249 #endif
27250 
27252  {
27253  // Create a new element from the communicated values
27254  // and coords from the process that located zeta
27255  GeneralisedElement *new_el_pt= new ELEMENT;
27256 
27257  // Add the new element to the mesh - Do not add the element yet
27258  // since no retained elements still need to be deleted
27259  // this->add_element_pt(new_el_pt);
27260 
27261  // Cast to the FE pointer
27262  FiniteElement* f_el_pt=dynamic_cast<FiniteElement*>(new_el_pt);
27263 
27264  // Add the element to the new elements in the domain container
27265  new_elements_on_domain.push_back(f_el_pt);
27266 
27267  // Set any additional information for the element
27268  this->add_element_load_balance_helper(iproc,
27269  received_old_haloed_element_pt,
27270  f_el_pt);
27271 
27272  // Add nodes to the new element
27273  unsigned n_node=f_el_pt->nnode();
27274  for (unsigned j=0;j<n_node;j++)
27275  {
27276  Node* new_nod_pt=0;
27277 
27278  // Call the add halo node helper function
27279  add_received_node_load_balance_helper(new_nod_pt,
27280  f_haloed_ele_pt,
27281  received_old_haloed_element_pt,
27282  new_nodes_on_domain,
27283  other_proc_shd_bnd_node_pt,
27284  iproc, j, f_el_pt,
27285  global_node_names,
27286  node_name_to_global_index,
27287  global_shared_node_pt);
27288  }
27289  }
27290  else // the element already exists
27291  {
27292 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27293  oomph_info
27294  << "Rec:" << Counter_for_flat_packed_unsigneds
27295  << " Index of existing element "
27297  << std::endl;
27298 #endif
27299 
27300  // Incrase the index, we do anything else with the element
27302 
27303  } // else the element already exists
27304 
27305  }
27306 
27307  //========start of add_element_load_balance_helper=====================
27308  /// \short Helper function to create elements on the loop
27309  /// process based on the info received in
27310  /// send_and_received_elements_nodes_info
27311  /// This function is in charge of verify if the element is associated
27312  /// to a boundary and associate to it if that is the case
27313  //======================================================================
27314  template<class ELEMENT>
27316  add_element_load_balance_helper(const unsigned &iproc,
27317  Vector<Vector<std::map<
27318  unsigned,FiniteElement*> > >
27319  &received_old_haloed_element_pt,
27320  FiniteElement* ele_pt)
27321  {
27322  // Get the number of processors
27323  const unsigned nproc = this->communicator_pt()->nproc();
27324 
27325 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27327  << " Bool: Element is associated to a boundary "
27329  << std::endl;
27330 #endif
27331 
27332  // Is on an original boundary?
27333  const unsigned is_on_original_boundary =
27335  if (is_on_original_boundary == 1)
27336  {
27337 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27338  oomph_info
27339  << "Rec:" << Counter_for_flat_packed_unsigneds
27340  << " How many boundaries are associated with the element "
27342  << std::endl;
27343 #endif
27344  // Number of boundaries the element is associated with
27345  const unsigned nassociated_boundaries =
27347 
27348  // Loop over the associated boundaries
27349  for (unsigned b = 0; b < nassociated_boundaries; b++)
27350  {
27351 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27352  oomph_info
27353  << "Rec:" << Counter_for_flat_packed_unsigneds
27354  << " Boundary associated to the element "
27356  << std::endl;
27357 #endif
27358 
27359  // The boundary id
27360  const unsigned bnd =
27362 
27363 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27364  oomph_info
27365  << "Rec:" << Counter_for_flat_packed_unsigneds
27366  << " Face index of the element "
27368  << std::endl;
27369 #endif
27370 
27371  // The face index
27372  const unsigned face_index =
27374 
27375  // Associate the element with the boundary and establish as many
27376  // face indexes it has
27377  this->Boundary_element_pt[bnd].push_back(ele_pt);
27378  this->Face_index_at_boundary[bnd].push_back(face_index);
27379 
27380  } // (b < nassociated_boundaries)
27381 
27382  // Here read the info. regarding the boundary-region of the element
27383 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27385  << " Bool: Element is associated to a boundary-region "
27387  << std::endl;
27388 #endif
27389 
27390  // Is the element associated to a boundary-region?
27392  {
27393 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27394  oomph_info
27395  << "Rec:" << Counter_for_flat_packed_unsigneds
27396  << " How many boundaries-regions are associated with the element "
27398  << std::endl;
27399 #endif
27400  // Number of boundary-regions the element is associated
27401  const unsigned nassociated_boundaries_and_regions =
27403 
27404  for (unsigned br = 0; br < nassociated_boundaries_and_regions; br++)
27405  {
27406 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27407  oomph_info
27408  << "Rec:" << Counter_for_flat_packed_unsigneds
27409  << " Boundary associated to the element "
27411  << std::endl;
27412 #endif
27413  // The boundary id
27414  const unsigned bnd =
27416 
27417 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27418  oomph_info
27419  << "Rec:" << Counter_for_flat_packed_unsigneds
27420  << " Region associated to the element "
27422  << std::endl;
27423 #endif
27424  // The region id
27425  const unsigned region =
27427 
27428 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27429  oomph_info
27430  << "Rec:" << Counter_for_flat_packed_unsigneds
27431  << " Face index of the element in boundary-region "
27433  << std::endl;
27434 #endif
27435  const unsigned face_index =
27437 
27438  // Associate the element with the boundary-regions and establish
27439  // as many face indexes it has
27440  this->Boundary_region_element_pt[bnd][region].push_back(ele_pt);
27441  this->Face_index_region_at_boundary[bnd][region].push_back(face_index);
27442 
27443  } // for (br < nassociated_boundaries_and_regions)
27444 
27445  } // Is the element associated with a boundary-region?
27446 
27447  } // The element is associated with an original boundary
27448 #ifdef PARANOID
27449  else
27450  {
27451  if (is_on_original_boundary != 0)
27452  {
27453  std::ostringstream error_message;
27454  error_message
27455  <<"The current element is not on an original boundary, this should\n"
27456  <<"be indicated by a zero flag. However, the read value for\n"
27457  <<"that flag is ("<<is_on_original_boundary<<").\n\n";
27458  throw OomphLibError(
27459  error_message.str(),
27460  "RefineableTriangleMesh::add_element_load_balance_helper()",
27461  OOMPH_EXCEPTION_LOCATION);
27462  } // if (is_on_shared_boundary != 0)
27463  }
27464 #endif
27465 
27466 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27468  << " Bool: Element is associated to a shared boundary "
27470  << std::endl;
27471 #endif
27472 
27473  // Is the element a shared boundary element?
27474  const unsigned is_on_shared_boundary =
27476  if (is_on_shared_boundary == 3)
27477  {
27478 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27479  oomph_info
27480  << "Rec:" << Counter_for_flat_packed_unsigneds
27481  << " How many shared boundaries are associated with the element "
27483  << std::endl;
27484 #endif
27485 
27486  // The number of shared boundaries the element is associated
27487  const unsigned nassociated_shared_boundaries =
27489 
27490  // Loop over the associated shared boundaries
27491  for (unsigned b = 0; b < nassociated_shared_boundaries; b++)
27492  {
27493 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27494  oomph_info
27495  << "Rec:" << Counter_for_flat_packed_unsigneds
27496  << " Shared boundary associated to the element "
27498  << std::endl;
27499 #endif
27500  const unsigned bnd =
27502 
27503 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27504  oomph_info
27505  << "Rec:" << Counter_for_flat_packed_unsigneds
27506  << " Face index of the element associated to the shared boundary "
27508  << std::endl;
27509 #endif
27510 
27511  const unsigned face_index =
27513 
27514  this->add_shared_boundary_element(bnd, ele_pt);
27515  this->add_face_index_at_shared_boundary(bnd, face_index);
27516 
27517  } // (b < nassociated_shared_boundaries)
27518 
27519  } // The element is associted with a shared boundary
27520 #ifdef PARANOID
27521  else
27522  {
27523  if (is_on_shared_boundary != 0)
27524  {
27525  std::ostringstream error_message;
27526  error_message
27527  <<"The current element is not on a shared boundary, this should\n"
27528  <<"be indicated by a zero flag. However, the read value for\n"
27529  <<"that flag is ("<<is_on_shared_boundary<<").\n\n";
27530  throw OomphLibError(
27531  error_message.str(),
27532  "RefineableTriangleMesh::add_element_load_balance_helper()",
27533  OOMPH_EXCEPTION_LOCATION);
27534  } // if (is_on_shared_boundary != 0)
27535  }
27536 #endif
27537 
27538  // Now check if the element is a haloed element in the sender
27539  // processor with any other processor
27540 
27541  // Loop over the processors
27542  for (unsigned jproc = 0; jproc < nproc; jproc++)
27543  {
27544 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27546  << " Bool: Number of haloed indexes of the element with the "
27547  << jproc << " processor: "
27549  << std::endl;
27550 #endif
27551  // Is the element haloed with the jproc processor
27552  const unsigned n_index_haloed_jproc =
27554  // Loop over the number of haloed indexes
27555  for (unsigned ihd = 0; ihd < n_index_haloed_jproc; ihd++)
27556  {
27557 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27559  << " Bool: The haloed element index with the "
27560  << jproc << " processor: "
27562  << std::endl;
27563 #endif
27564  const unsigned haloed_index =
27566 
27567  // Set the halod element in the proper storage
27568  received_old_haloed_element_pt[iproc][jproc][haloed_index] = ele_pt;
27569 
27570  } // for (ihd < n_index_haloed_jproc)
27571 
27572  } // for (jproc < nproc)
27573 
27574  }
27575 
27576  //======================================================================
27577  /// \short Helper function to add a new node from load balance
27578  //======================================================================
27579  template <class ELEMENT>
27583  &f_haloed_ele_pt,
27584  Vector<Vector<std::map<
27585  unsigned,FiniteElement*> > >
27586  &received_old_haloed_element_pt,
27587  Vector<Node*> &new_nodes_on_domain,
27589  std::map<unsigned, Node*> > > >
27590  &other_proc_shd_bnd_node_pt,
27591  unsigned& iproc,
27592  unsigned& node_index,
27593  FiniteElement* const &new_el_pt,
27595  &global_node_names,
27596  std::map<Vector<unsigned>, unsigned>
27597  &node_name_to_global_index,
27598  Vector<Node*> &global_shared_node_pt)
27599  {
27600  // Given the node, received information about it from processor
27601  // iproc, construct it on the current process
27602 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27604  << " Bool: New node needs to be constructed "
27606  << std::endl;
27607 #endif
27609  {
27610  // Construct a new node based upon sent information, or copy a node
27611  // from one of the shared boundaries
27612  construct_new_node_load_balance_helper(new_nod_pt,
27613  f_haloed_ele_pt,
27614  received_old_haloed_element_pt,
27615  new_nodes_on_domain,
27616  other_proc_shd_bnd_node_pt,
27617  iproc,
27618  node_index,
27619  new_el_pt,
27620  global_node_names,
27621  node_name_to_global_index,
27622  global_shared_node_pt);
27623  }
27624  else
27625  {
27626 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27628  << " Index of existing halo node "
27630  << std::endl;
27631 #endif
27632  // The node already exist, copy it from the indicated position
27633 
27634  // Get the node's index, and copy it
27635  new_nod_pt = new_nodes_on_domain[
27637 
27638  // Set the node in the current element
27639  new_el_pt->node_pt(node_index) = new_nod_pt;
27640 
27641  }
27642 
27643  }
27644 
27645  //============start_of_construct_new_node_load_balance_helper()=========
27646  /// \short Helper function which constructs a new node (on an
27647  /// element) with the information sent from the load balance
27648  /// process
27649  //======================================================================
27650  template<class ELEMENT>
27653  Node* &new_nod_pt,
27654  Vector<Vector<FiniteElement*> > &f_haloed_ele_pt,
27655  Vector<Vector<std::map<unsigned,FiniteElement*> > >
27656  &received_old_haloed_element_pt,
27657  Vector<Node*> &new_nodes_on_domain,
27658  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
27659  &other_proc_shd_bnd_node_pt,
27660  unsigned& iproc, unsigned& node_index,
27661  FiniteElement* const &new_el_pt,
27662  Vector<Vector<Vector<unsigned> > > &global_node_names,
27663  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
27664  Vector<Node*> &global_shared_node_pt)
27665  {
27666  // Get the number of processors
27667  const unsigned nproc = this->communicator_pt()->nproc();
27668  // Get the rank of the current processor
27669  const unsigned my_rank = this->communicator_pt()->my_rank();
27670 
27671  //The first entry indicates the number of values at this new Node
27672  //(which may be different across the same element e.g. Lagrange multipliers)
27673 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27675  << " Number of values of external halo node "
27677  << std::endl;
27678 #endif
27680 
27681  // Null TimeStepper for now
27682  TimeStepper* time_stepper_pt=this->Time_stepper_pt;
27683  // Default number of previous values to 1
27684  unsigned n_prev=time_stepper_pt->ntstorage();
27685 
27686  // ------------------------------------------------------
27687  // Check if the node is on an original boundary
27688 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27690  << " Is the node on an original boundary "
27692  << std::endl;
27693 #endif
27694 
27695  // Flag to indicate if the node is on original boundaries
27696  const unsigned node_on_original_boundaries =
27698 
27699  // Store the original boundaries where the node is on
27700  Vector<unsigned> original_boundaries_node_is_on;
27701  // Store the zeta coordinates of the node on the original boundaries
27702  Vector<double> zeta_coordinates;
27703  // Store the number of original boundaries the node is on
27704  unsigned n_original_boundaries_node_is_on = 0;
27705 
27706  if (node_on_original_boundaries==2)
27707  {
27708  // How many original boundaries does the node live on?
27709 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27711  << " Number of boundaries the node is on: "
27713  << std::endl;
27714 #endif
27715  n_original_boundaries_node_is_on =
27717 
27718  // Resize the containers
27719  original_boundaries_node_is_on.resize(n_original_boundaries_node_is_on);
27720  zeta_coordinates.resize(n_original_boundaries_node_is_on);
27721 
27722  for (unsigned i=0;i<n_original_boundaries_node_is_on;i++)
27723  {
27724  // Boundary number
27725 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27727  << " Node is on boundary "
27729  << std::endl;
27730 #endif
27731  original_boundaries_node_is_on[i] =
27733  zeta_coordinates[i] =
27735  }
27736 
27737  } // if (node_on_original_boundaries==2)
27738 #ifdef PARANOID
27739  else
27740  {
27741  if (node_on_original_boundaries != 0)
27742  {
27743  std::ostringstream error_message;
27744  error_message
27745  <<"The current node is not on an original boundary, this should\n"
27746  <<"be indicated by a zero flag. However, the read value for\n"
27747  <<"that flag is ("<<node_on_original_boundaries<<").\n\n";
27748  throw OomphLibError(
27749  error_message.str(),
27750  "RefineableTriangleMesh::construct_new_halo_node_helper()",
27751  OOMPH_EXCEPTION_LOCATION);
27752  } // if (node_on_original_boundaries != 0)
27753  }
27754 #endif
27755 
27756  // --------------------------------------------------------------
27757  // Check if the node was on a shared boundary with the iproc
27758  // processor
27759 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27761  << " Is node on shared boundary? "
27763  << std::endl;
27764 #endif
27765  const unsigned is_node_on_shared_boundary =
27767  if (is_node_on_shared_boundary == 1)
27768  {
27769  // How many shared boundaries does the node live on?
27770 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27772  << " Number of boundaries the node is on: "
27774  << std::endl;
27775 #endif
27776  const unsigned n_shd_bnd_node_is_on =
27778  Vector<unsigned> shd_bnds_node_is_on(n_shd_bnd_node_is_on);
27779  for (unsigned i=0;i<n_shd_bnd_node_is_on;i++)
27780  {
27781  // Shared boundary number
27782 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27784  << " Node is on boundary "
27786  << std::endl;
27787 #endif
27788  shd_bnds_node_is_on[i] =
27790  }
27791 
27792  // Get the index of the node on the shared boundary
27793 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27795  << " Index of node on boundary "
27797  << std::endl;
27798 #endif
27799  // Get the node index of the node on the shared boundary
27800  unsigned node_index_on_shared_boundary =
27802 
27803  // Get the pointer to the node with the received info.
27804  new_nod_pt =
27805  this->sorted_shared_boundary_node_pt(shd_bnds_node_is_on[0],
27806  node_index_on_shared_boundary);
27807 
27808  } // if (is_node_on_shared_boundary == 1)
27809 #ifdef PARANOID
27810  else
27811  {
27812  if (is_node_on_shared_boundary != 0)
27813  {
27814  std::ostringstream error_message;
27815  error_message
27816  <<"The current node is not on a shared boundary, this should\n"
27817  <<"be indicated by a zero flag. However, the read value for\n"
27818  <<"that flag is ("<<is_node_on_shared_boundary<<").\n\n";
27819  throw OomphLibError(
27820  error_message.str(),
27821  "RefineableTriangleMesh::construct_new_halo_node_helper()",
27822  OOMPH_EXCEPTION_LOCATION);
27823  } // if (node_on_shared_boundary != 0)
27824  }
27825 #endif
27826 
27827  // ------------------------------------------------------------
27828  // Is the node on a shared boundary with other processor?
27829 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27831  << " Is the node on shared boundaries with other processors "
27833  << std::endl;
27834 #endif
27835 
27836  // Is the node in shared boundaries no associated with the
27837  // receiver processor
27838  const unsigned is_the_node_in_shared_boundaries_with_other_processors =
27840 
27841  // The containers where to store the info.
27842  Vector<unsigned> other_processor_1;
27843  Vector<unsigned> other_processor_2;
27844  Vector<unsigned> other_shared_boundaries;
27845  Vector<unsigned> other_indexes;
27846 
27847  // How many shared bounaries with other processors the node lives on
27848  unsigned n_shd_bnd_with_other_procs_have_node = 0;
27849 
27850  // Is the node on shared boundaries with other processors
27851  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
27852  {
27853 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27855  << " In how many shared boundaries with other "
27856  << "processors is the node "
27858  << std::endl;
27859 #endif
27860 
27861  // How many nodes on other shared boundaries were found
27862  n_shd_bnd_with_other_procs_have_node =
27864 
27865  // Resize the containers
27866  other_processor_1.resize(n_shd_bnd_with_other_procs_have_node);
27867  other_processor_2.resize(n_shd_bnd_with_other_procs_have_node);
27868  other_shared_boundaries.resize(n_shd_bnd_with_other_procs_have_node);
27869  other_indexes.resize(n_shd_bnd_with_other_procs_have_node);
27870 
27871  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
27872  {
27873 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27875  << " Processor where the other shared boundary"
27876  << "has the node"
27878  << std::endl;
27879 #endif
27880  // Read the other processor 1
27881  other_processor_1[i] =
27883 
27884 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27886  << " Processor where the other shared boundary"
27887  << "has the node"
27889  << std::endl;
27890 #endif
27891  // Read the other processor 2
27892  other_processor_2[i] =
27894 
27895 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27897  << " Other shared boundary id where the node is on: "
27899  << std::endl;
27900 #endif
27901 
27902  // Read the other shared boundary id
27903  other_shared_boundaries[i] =
27905 
27906 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27908  << " Node index on the other shared boundary "
27910  << std::endl;
27911 #endif
27912 
27913  // Read the node index on the other shared boundary
27914  other_indexes[i] =
27916 
27917  } // for (i < n_shd_bnd_with_other_procs_have_node)
27918 
27919  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
27920 #ifdef PARANOID
27921  else
27922  {
27923  if (is_the_node_in_shared_boundaries_with_other_processors != 0)
27924  {
27925  std::ostringstream error_message;
27926  error_message
27927  <<"The current node is not on a shared boundary with\n"
27928  <<"other processors, this should be indicated by a zero flag.\n"
27929  <<"However, the read value for that flag is ("
27930  <<is_the_node_in_shared_boundaries_with_other_processors<<").\n\n";
27931  throw OomphLibError(
27932  error_message.str(),
27933  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
27934  OOMPH_EXCEPTION_LOCATION);
27935  }
27936  }
27937 #endif
27938 
27939  // ------------------------------------------------------------
27940  // Receive the info. to check if the node is on a haloed element
27941  // with any processor
27942 
27943  // Store the halo element number with jproc where the node was found
27944  Vector<Vector<unsigned> > halo_element_number(nproc);
27945  // Store the node number on the halo element where the node was found
27946  Vector<Vector<unsigned> > halo_node_number_in_halo_element(nproc);
27947 
27948  // Loop over the processors
27949  for (unsigned jproc = 0; jproc < nproc; jproc++)
27950  {
27951 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27953  << " The node is on "
27955  << " halo elements with " << jproc << " processor"
27956  << std::endl;
27957 #endif
27958  // Get the number of halo elements with jproc processor where the
27959  // node was found
27960  const unsigned n_jproc_halo_ele_node_is_on =
27962 
27963  // Resize the containers
27964  halo_element_number[jproc].resize(n_jproc_halo_ele_node_is_on);
27965  halo_node_number_in_halo_element[jproc].resize(n_jproc_halo_ele_node_is_on);
27966 
27967  // Read halo elements indexes (which are indexes of the halo
27968  // elements of the sender processor (iproc) with other processors
27969  // (included my_rank)
27970  for (unsigned i = 0; i < n_jproc_halo_ele_node_is_on; i++)
27971  {
27972  // Get the halo element index in the jproc processor
27973 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27975  << " The halo element index where the node is on "
27977  << std::endl;
27978 #endif
27979  // Get the node index on the halo element
27980  const unsigned halo_ele_index =
27982 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27984  << " The node index on the halo element where the node "
27985  << "is on "
27987  << std::endl;
27988 #endif
27989  const unsigned node_index_on_halo_ele =
27991 
27992  // Store the halo element number
27993  halo_element_number[jproc][i] = halo_ele_index;
27994  // Store the index of on the haloed element
27995  halo_node_number_in_halo_element[jproc][i] = node_index_on_halo_ele;
27996 
27997  } // for (i < n_jproc_halo_ele_node_is_on)
27998 
27999  } // for (jproc < nproc)
28000 
28001  // Store the node pointers obtained from the indicated halo elements
28002  // (use a set to check for the case when the node pointer is
28003  // different)
28004  std::set<Node*> set_haloed_node_pt;
28005 
28006  // Store the node pointer obtained from the haloed elements
28007  Node* haloed_node_pt = 0;
28008 
28009  // Flag to indicate if it is on a haloed element of the current
28010  // processor with the iproc processor. If this flag is true then
28011  // there is no need to read the info. to create the node, only copy
28012  // the node from the indicated haloed element-node
28013  bool on_haloed_element_with_iproc_processor = false;
28014  if (halo_element_number[my_rank].size() > 0)
28015  {
28016  // The node is part of the haloed element in the current processor
28017  // (my_rank) with the receiver processor
28018  on_haloed_element_with_iproc_processor = true;
28019 
28020  // Get the number of haloed elements in the current processor
28021  const unsigned n_haloed_indexes = halo_element_number[my_rank].size();
28022  // Loop over the different haloed indexes, and get the nodes
28023  // instances from all the indicated haloed elements (all of them
28024  // should be the same)
28025  for (unsigned i = 0; i < n_haloed_indexes; i++)
28026  {
28027  // Get the haloed element numbers where the node is on
28028  const unsigned haloed_index = halo_element_number[my_rank][i];
28029  // Get the node index on the haloed element
28030  const unsigned haloed_node_index =
28031  halo_node_number_in_halo_element[my_rank][i];
28032 
28033  // Get the haloed element (with iproc)
28034  FiniteElement* tmp_haloed_ele_pt = f_haloed_ele_pt[iproc][haloed_index];
28035  // Get the node on the indicated node number
28036  Node* tmp_haloed_node_pt = tmp_haloed_ele_pt->node_pt(haloed_node_index);
28037 
28038  // Set the pointer for the obtained haloed node
28039  haloed_node_pt = tmp_haloed_node_pt;
28040 
28041  // Add the node to the set of node pointers
28042  set_haloed_node_pt.insert(tmp_haloed_node_pt);
28043 
28044 #ifdef PARANOID
28045  if (set_haloed_node_pt.size() > 1)
28046  {
28047  std::ostringstream error_message;
28048  error_message
28049  <<"When adding the " << haloed_node_index << " node of the "
28050  << haloed_index << "-th haloed element\n"
28051  << "in the currrent processor with the " << iproc << " processor"
28052  << "it was found that\nthe node pointer is different from the other"
28053  << "instances of the node.\nIt means we have a repeated node."
28054  << "This are the node coordinates of the previous node instances\n"
28055  << "The last entry is for the just added node with a different node\n"
28056  << "pointer\n";
28057  for (std::set<Node*>::iterator it = set_haloed_node_pt.begin();
28058  it != set_haloed_node_pt.end(); it++)
28059  {
28060  error_message
28061  << "Node: ("<< (*it)->x(0)<<", "<<(*it)->x(1)<<")\n";
28062  }
28063  error_message << "\n";
28064  throw OomphLibError(
28065  error_message.str(),
28066  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
28067  OOMPH_EXCEPTION_LOCATION);
28068  }
28069 #endif
28070 
28071  } // for (i < n_haloed_indexes)
28072 
28073  } // if (halo_element_number[iproc].size() > 0)
28074 
28075  // Flag to indicate if the node has been found on a haloed element
28076  // of other processor with the iproc processor
28077  bool found_on_haloed_element_with_other_processor = false;
28078  // Loop over the processors (only until the iproc since no info. of
28079  // higher processors has been received)
28080  for (unsigned jproc = 0; jproc < iproc; jproc++)
28081  {
28082  // Is the node on a halo element with the jproc processor
28083  if (halo_element_number[jproc].size() > 0)
28084  {
28085  // Get the number of halo elements with the jproc processor
28086  const unsigned n_halo_indexes = halo_element_number[jproc].size();
28087  // Loop over the different halo indexes, and get the nodes
28088  // instances from all the indicated halo elements (all of them
28089  // should be the same)
28090  for (unsigned i = 0; i < n_halo_indexes; i++)
28091  {
28092  // Get the haloed element numbers where the node is on
28093  const unsigned haloed_index = halo_element_number[jproc][i];
28094  // Get the node index on the haloed element
28095  const unsigned haloed_node_index =
28096  halo_node_number_in_halo_element[jproc][i];
28097 
28098  // Have we received the indicated element? (Get the haloed
28099  // element on jproc with the iproc processor)
28100  std::map<unsigned,FiniteElement*>::iterator it_map =
28101  received_old_haloed_element_pt[jproc][iproc].find(haloed_index);
28102  // Have we received the indicated element?
28103  if (it_map != received_old_haloed_element_pt[jproc][iproc].end())
28104  {
28105  // Set the flag of found element in other processors haloed
28106  // element, in this case in haloed elements of processor
28107  // jproc wiht iproc processor
28108  found_on_haloed_element_with_other_processor = true;
28109 
28110  // Get the element
28111  FiniteElement* tmp_haloed_ele_pt = (*it_map).second;
28112  // Get the node on the indicated node number
28113  Node* tmp_haloed_node_pt =
28114  tmp_haloed_ele_pt->node_pt(haloed_node_index);
28115 
28116  // Set the pointer for the obtained haloed node
28117  haloed_node_pt = tmp_haloed_node_pt;
28118 
28119  // Add the node to the set of node pointers
28120  set_haloed_node_pt.insert(tmp_haloed_node_pt);
28121 
28122 #ifdef PARANOID
28123  if (set_haloed_node_pt.size() > 1)
28124  {
28125  std::ostringstream error_message;
28126  error_message
28127  <<"When adding the " << haloed_node_index << " node of the "
28128  << haloed_index << "-th haloed element "
28129  << "of the " << jproc << " processor\nwith the "
28130  << iproc << " processor, it was found that\n"
28131  << "the node pointer is different from the other\n"
28132  << "instances of the node.\nThis means we have a repeated node.\n"
28133  << "These are the node coordinates of the previous node "
28134  << "instances\n"
28135  << "The last entry is for the just added node with a different\n"
28136  << "node pointer\n";
28137  for (std::set<Node*>::iterator it = set_haloed_node_pt.begin();
28138  it != set_haloed_node_pt.end(); it++)
28139  {
28140  error_message
28141  << "Node: ("<< (*it)->x(0)<<", "<<(*it)->x(1)<<")\n";
28142  }
28143  error_message << "\n";
28144  throw OomphLibError(
28145  error_message.str(),
28146  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
28147  OOMPH_EXCEPTION_LOCATION);
28148  }
28149 #endif
28150 
28151  } // if (it_map != received_old_haloed_element_pt[jproc][iproc].end())
28152  // Have we received the element?
28153 
28154  } // for (i < n_haloed_indexes)
28155 
28156  } // if (halo_element_number[iproc].size() > 0)
28157 
28158  } // for (jproc < nproc)
28159 
28160  // If the node was found in the haloed elements of the current
28161  // processor with the iproc processor, or in the haloed elements of
28162  // any other processor with the iproc processor then copy the node
28163  // pointer (no problem if we overwrite the node info. it should be
28164  // the same node pointer)
28165  if (on_haloed_element_with_iproc_processor ||
28166  found_on_haloed_element_with_other_processor)
28167  {
28168  // Set the node pointer
28169  new_nod_pt = haloed_node_pt;
28170  }
28171 
28172  // Now we have all the info. to decide if the node should be created
28173  // or not
28174 
28175  // First check if the node is a shared boundary node, or if it has
28176  // been found on haloed elements
28177  if (is_node_on_shared_boundary == 1 ||
28178  (on_haloed_element_with_iproc_processor))
28179  {
28180  // We already have the node, we do not need to create it
28181 
28182  // Only check if we need to add boundary info. to the node
28183  if (node_on_original_boundaries==2)
28184  {
28185  // The node is a boundary node, add the boundary info. before
28186  // adding it to the domain
28187 
28188  // Associate the node to the given boundaries
28189  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
28190  {
28191  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
28192  // Establish the boundary coordinates for the node
28193  Vector<double> zeta(1);
28194  zeta[0] = zeta_coordinates[i];
28195  new_nod_pt->set_coordinates_on_boundary(
28196  original_boundaries_node_is_on[i],zeta);
28197  }
28198 
28199  } // if (node_on_original_boundaries==2)
28200 
28201  // Add the node to the domain
28202  new_nodes_on_domain.push_back(new_nod_pt);
28203 
28204  // Add the node to the element
28205  new_el_pt->node_pt(node_index) = new_nod_pt;
28206 
28207  } // if (is_node_on_shared_boundary == 1)
28208 
28209  // Now check if the node is on a shared boundary with another
28210  // processor, if that is the case try to find the node that may have
28211  // been already sent by the other processors
28212 
28213  // This flags indicates if the node was found, and then decide if it
28214  // is required to create the node
28215  bool found_node_in_other_shared_boundaries = false;
28216  // Flag to indicate whether the node should be created as a boundary
28217  // node or not. If the node lies on a shared boundary with other
28218  // processor the we create it as a boundary node. The processor from
28219  // which we are receiving info. (iproc) may not know that the node
28220  // lies on an original boundary. If the node lies on an original
28221  // boundary then its info. will be sent by another processor, then
28222  // we can set its boundary info. since the node was constructed as a
28223  // boundary node
28224  bool build_node_as_boundary_node = false;
28225 
28226  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28227  {
28228  // Build the node as a boundary node
28229  build_node_as_boundary_node = true;
28230 
28231  // Try to get the node pointer in case that the node has been
28232  // already sent by the other processors
28233 
28234  // Get the number of initial shared boundaries to correct the
28235  // index of the shared boundary
28236  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
28237 
28238  // Add the found nodes in the container, should be the same but
28239  // better check
28240  Vector<Node*> found_node_pt;
28241 
28242  // Now try to find the node in any of the other shared boundaries
28243  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
28244  {
28245  unsigned oproc1 = other_processor_1[i];
28246  unsigned oproc2 = other_processor_2[i];
28247 
28248  // Check that we always check with the lower processors number
28249  // first
28250  if (oproc1 > oproc2)
28251  {
28252  oproc2 = oproc1;
28253  oproc1 = other_processor_2[i];
28254  } // if (oproc1 > oproc2)
28255 
28256  // Re-compute the shared boundary id between the other
28257  // processors
28258  const unsigned shd_bnd_id =
28259  other_shared_boundaries[i] - initial_shd_bnd_id;
28260  // Read the index
28261  const unsigned index = other_indexes[i];
28262 
28263  // Check if there are nodes received from the other processor
28264  // and with the given shared boundary
28265  const unsigned n_nodes_on_other_processor =
28266  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].size();
28267 
28268  if (n_nodes_on_other_processor > 0)
28269  {
28270  // Check if we can find the index of the node in that other
28271  // processor and shared boundary id
28272  std::map<unsigned, Node*>::iterator it =
28273  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].
28274  find(index);
28275 
28276  // If the index exist then get the node pointer
28277  if (it!=
28278  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
28279  {
28280  // Mark the node as found
28281  found_node_in_other_shared_boundaries = true;
28282  // Get the node pointer
28283  Node* tmp_node_pt =
28284  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id][index];
28285  found_node_pt.push_back(tmp_node_pt);
28286  } // if (it!=
28287  // other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
28288 
28289  } // if (n_nodes_on_other_processor > 0)
28290 
28291  } // for (i < n_shd_bnd_with_other_procs_have_node)
28292 
28293  // If the node was found, then all their instances should be the
28294  // same but better check
28295  if (found_node_in_other_shared_boundaries)
28296  {
28297 #ifdef PARANOID
28298  const unsigned ntimes_node_found = found_node_pt.size();
28299  for (unsigned j = 1; j < ntimes_node_found; j++)
28300  {
28301  if (found_node_pt[j-1] != found_node_pt[j])
28302  {
28303  std::ostringstream error_message;
28304  error_message
28305  <<"The instances of the node that was found to be on a\n"
28306  <<"shared boundary with other processors are not the same,\n"
28307  <<"the coordinates for the nodes are these:\n"
28308  <<"(" << found_node_pt[j-1]->x(0) << ", "
28309  << found_node_pt[j-1]->x(1) << ")\n"
28310  <<"(" << found_node_pt[j]->x(0) << ", "
28311  << found_node_pt[j]->x(1) << ")\n"
28312  <<"Not be surprised if they are the same since the node is\n"
28313  <<"repeated!!!\n";
28314  throw OomphLibError(
28315  error_message.str(),
28316  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28317  OOMPH_EXCEPTION_LOCATION);
28318 
28319  } // if (found_node_pt[j-1] != found_node_pt[j])
28320 
28321  } // for (j < ntimes_node_found)
28322 #endif
28323 
28324  // Check if the node is a shared boundary node from the current
28325  // processor and the iproc processor, if that is the case, and
28326  // the node is also on a shared boundary with other processor,
28327  // then the pointer should be the same!!!
28328  if (is_node_on_shared_boundary == 1)
28329  {
28330  // The pointer to the node is already assigned, it was
28331  // assigned when thenode was found to be on a shared boundary
28332  // with the iproc processor
28333  if (found_node_pt[0] != new_nod_pt)
28334  {
28335  std::ostringstream error_message;
28336  error_message
28337  <<"The pointer of the node that was found to be on a\n"
28338  <<"shared boundary with other processor(s) and the pointer\n"
28339  <<"of the node on shared boundary with the receiver\n"
28340  <<"processor (iproc) are not the same. This means we have a\n"
28341  << "repeated node)\n"
28342  <<"The coordinates for the nodes are:\n"
28343  <<"(" << found_node_pt[0]->x(0) << ", "
28344  << found_node_pt[0]->x(1) << ")\n"
28345  <<"(" << new_nod_pt->x(0) << ", "
28346  << new_nod_pt->x(1) << ")\n"
28347  <<"Not to be surprised if they are the same since the node is\n"
28348  <<"repeated!!!\n";
28349  throw OomphLibError(
28350  error_message.str(),
28351  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28352  OOMPH_EXCEPTION_LOCATION);
28353  } // if (found_node_pt[0] != new_nod_pt)
28354 
28355  } // if (is_node_on_shared_boundary == 1)
28356  else
28357  {
28358  // Take the first instance of the node in case that it was
28359  // found and is not on a shared boundary with the iproc
28360  // processor
28361  new_nod_pt = found_node_pt[0];
28362  }
28363 
28364  } // if (found_node_in_other_shared_boundaries)
28365 
28366  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28367 
28368  // -----------------------------------------------------------------
28369  // Create the node or read the received info if the node is not on a
28370  // shared boundary with the iproc processor and if the node is not
28371  // part of the haloed elements with the iproc processor in the
28372  // current processors
28373  if (is_node_on_shared_boundary != 1 &&
28374  !on_haloed_element_with_iproc_processor)
28375  {
28376  // If the node is on a shared boundary with other processor we
28377  // need to read all the info. since the processor that sent the
28378  // info. did not know that the node is part of another shared
28379  // boundary
28380 
28381  // If the node is not a shared boundary (with any processor), or
28382  // if this is the first time that the info. of the node is
28383  // received from any of the processors with which is has a shared
28384  // boundary, then we create the node
28385 
28386  // Is the node a boundary node or should it be build as a boundary
28387  // node because it is on a shared boundary with other processors
28388  if (node_on_original_boundaries==2 || build_node_as_boundary_node)
28389  {
28390  // Check if necessary to create the node, or if it has been
28391  // already found in shared boundaries with other processors or
28392  // in the haloed elements with of other processors with the
28393  // iproc processor
28394  if (!found_node_in_other_shared_boundaries ||
28395  !found_on_haloed_element_with_other_processor)
28396  {
28397  // Construct a boundary node
28398  if (time_stepper_pt!=0)
28399  {
28400  new_nod_pt=new_el_pt->construct_boundary_node(node_index,
28401  time_stepper_pt);
28402  }
28403  else
28404  {
28405  new_nod_pt=new_el_pt->construct_boundary_node(node_index);
28406  }
28407 
28408  } // if (!found_node_in_other_shared_boundaries ||
28409  // !found_on_haloed_element_with_other_processor)
28410  else
28411  {
28412  // If the node was found then assign the node to the element
28413  new_el_pt->node_pt(node_index) = new_nod_pt;
28414  } // else if (!found_node_in_other_shared_boundaries ||
28415  // !found_on_haloed_element_with_other_processor)
28416 
28417  // Associate the node to the given boundaries
28418  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
28419  {
28420  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
28421  // Establish the boundary coordinates for the node
28422  Vector<double> zeta(1);
28423  zeta[0] = zeta_coordinates[i];
28424  new_nod_pt->set_coordinates_on_boundary(
28425  original_boundaries_node_is_on[i],zeta);
28426  }
28427 
28428  } // if (node is on an original boundary)
28429  else
28430  {
28431  // Check if necessary to create the node, or if it has been
28432  // already found in shared boundaries with other processors or
28433  // in the haloed elements with of other processors with the
28434  // iproc processor
28435  if (!found_node_in_other_shared_boundaries ||
28436  !found_on_haloed_element_with_other_processor)
28437  {
28438  // Construct an ordinary (non-boundary) node
28439  if (time_stepper_pt!=0)
28440  {
28441  new_nod_pt=new_el_pt->construct_node(node_index, time_stepper_pt);
28442  }
28443  else
28444  {
28445  new_nod_pt=new_el_pt->construct_node(node_index);
28446  }
28447  } // if (!found_node_in_other_shared_boundaries ||
28448  // !found_on_haloed_element_with_other_processor)
28449  else
28450  {
28451  // If the node was found then assign the node to the element
28452  new_el_pt->node_pt(node_index) = new_nod_pt;
28453  } // else // if (!found_node_in_other_shared_boundaries ||
28454  // !found_on_haloed_element_with_other_processor)
28455 
28456  } // else (the node is not a boundary node)
28457 
28458  // ... and gather all its information
28459 
28460  // If the node was found or not in other shared boundaries, this
28461  // is the first time the node is received from this processor
28462  // (iproc), therefore it is added to the vector of nodes received
28463  // from this processor (iproc)
28464  new_nodes_on_domain.push_back(new_nod_pt);
28465 
28466  // Check if necessary to state all the info. to the node if it has
28467  // been already found in shared boundaries with other processors
28468  // or in the haloed elements with of other processors with the
28469  // iproc processor
28470  if (!found_node_in_other_shared_boundaries ||
28471  !found_on_haloed_element_with_other_processor)
28472  {
28473  // Add the node to the general node storage
28474  this->add_node_pt(new_nod_pt);
28475  } // if (!found_node_in_other_shared_boundaries ||
28476  // !found_on_haloed_element_with_other_processor)
28477 
28478  // Is the new constructed node Algebraic?
28479  AlgebraicNode* new_alg_nod_pt=dynamic_cast<AlgebraicNode*>
28480  (new_nod_pt);
28481 
28482  // If it is algebraic, its node update functions will
28483  // not yet have been set up properly
28484  if (new_alg_nod_pt!=0)
28485  {
28486  // The AlgebraicMesh is the external mesh
28487  AlgebraicMesh* alg_mesh_pt=dynamic_cast<AlgebraicMesh*>(this);
28488 
28489  /// The first entry of All_alg_nodal_info contains
28490  /// the default node update id
28491  /// e.g. for the quarter circle there are
28492  /// "Upper_left_box", "Lower right box" etc...
28493 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28495  << " Alg node update id "
28497  << std::endl;
28498 #endif
28499 
28500  unsigned update_id=Flat_packed_unsigneds
28502 
28503  Vector<double> ref_value;
28504 
28505  // The size of this vector is in the next entry
28506  // of All_alg_nodal_info
28507 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28509  << " Alg node # of ref values "
28511  << std::endl;
28512 #endif
28513  unsigned n_ref_val=Flat_packed_unsigneds
28515 
28516  // The reference values themselves are in
28517  // All_alg_ref_value
28518  ref_value.resize(n_ref_val);
28519  for (unsigned i_ref=0;i_ref<n_ref_val;i_ref++)
28520  {
28521  ref_value[i_ref]=Flat_packed_doubles
28523  }
28524 
28525  Vector<GeomObject*> geom_object_pt;
28526  /// again we need the size of this vector as it varies
28527  /// between meshes; we also need some indication
28528  /// as to which geometric object should be used...
28529 
28530  // The size of this vector is in the next entry
28531  // of All_alg_nodal_info
28532 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28534  << " Alg node # of geom objects "
28536  << std::endl;
28537 #endif
28538  unsigned n_geom_obj=Flat_packed_unsigneds
28540 
28541  // The remaining indices are in the rest of
28542  // All_alg_nodal_info
28543  geom_object_pt.resize(n_geom_obj);
28544  for (unsigned i_geom=0;i_geom<n_geom_obj;i_geom++)
28545  {
28546 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28548  << " Alg node: geom object index "
28550  << std::endl;
28551 #endif
28552  unsigned geom_index=Flat_packed_unsigneds
28554  // This index indicates which of the AlgebraicMesh's
28555  // stored geometric objects should be used
28556  // (0 is a null pointer; everything else should have
28557  // been filled in by the specific Mesh). If it
28558  // hasn't been filled in then the update_node_update
28559  // call should fix it
28560  geom_object_pt[i_geom]=alg_mesh_pt->
28561  geom_object_list_pt(geom_index);
28562  }
28563 
28564  // Check if necessary to state all the info. to the node if it
28565  // has been already found in shared boundaries with other
28566  // processors or in the haloed elements with of other processors
28567  // with the iproc processor
28568  if (!found_node_in_other_shared_boundaries ||
28569  !found_on_haloed_element_with_other_processor)
28570  {
28571  /// For the received update_id, ref_value, geom_object
28572  /// call add_node_update_info
28573  new_alg_nod_pt->add_node_update_info
28574  (update_id,alg_mesh_pt,geom_object_pt,ref_value);
28575 
28576  /// Now call update_node_update
28577  alg_mesh_pt->update_node_update(new_alg_nod_pt);
28578 
28579  } // if (!found_node_in_other_shared_boundaries ||
28580  // !found_on_haloed_element_with_other_processor)
28581 
28582  } // if (new_alg_nod_pt!=0)
28583 
28584  // Check if necessary to state all the info. to the node if it has
28585  // been already found in shared boundaries with other processors
28586  // or in the haloed elements with of other processors with the
28587  // iproc processor
28588  if (!found_node_in_other_shared_boundaries ||
28589  !found_on_haloed_element_with_other_processor)
28590  {
28591  // Is the node a MacroElementNodeUpdateNode?
28592  MacroElementNodeUpdateNode* macro_nod_pt=
28593  dynamic_cast<MacroElementNodeUpdateNode*>(new_nod_pt);
28594 
28595  if (macro_nod_pt!=0)
28596  {
28597  // Need to call set_node_update_info; this requires
28598  // a Vector<GeomObject*> (taken from the mesh)
28599  Vector<GeomObject*> geom_object_vector_pt;
28600 
28601  // Access the required geom objects from the
28602  // MacroElementNodeUpdateMesh
28603  MacroElementNodeUpdateMesh* macro_mesh_pt=
28604  dynamic_cast<MacroElementNodeUpdateMesh*>(this);
28605  geom_object_vector_pt=
28606  macro_mesh_pt->geom_object_vector_pt();
28607 
28608  // Get local coordinate of node in new element
28609  Vector<double> s_in_macro_node_update_element;
28610  new_el_pt->local_coordinate_of_node
28611  (node_index,s_in_macro_node_update_element);
28612 
28613  // Set node update info for this node
28614  macro_nod_pt->set_node_update_info
28615  (new_el_pt,s_in_macro_node_update_element,
28616  geom_object_vector_pt);
28617  }
28618 
28619  } // if (!found_node_in_other_shared_boundaries ||
28620  // !found_on_haloed_element_with_other_processor)
28621 
28622  // If there are additional values, resize the node
28623  unsigned n_new_val=new_nod_pt->nvalue();
28624 
28625  // Check if necessary to state all the info. to the node if it has
28626  // been already found in shared boundaries with other processors
28627  // or in the haloed elements with of other processors with the
28628  // iproc processor
28629  if (!found_node_in_other_shared_boundaries ||
28630  !found_on_haloed_element_with_other_processor)
28631  {
28632  if (n_val>n_new_val)
28633  {
28634  // If it has been necessary to resize then it may be becuse
28635  // the node is on a FSI boundary, if that is the case we need
28636  // to set a map for these external values
28637 
28638  // Cast to a boundary node
28639  BoundaryNodeBase *bnod_pt =
28640  dynamic_cast<BoundaryNodeBase*>(new_nod_pt);
28641 
28642  // Create storage, if it doesn't already exist, for the map
28643  // that will contain the position of the first entry of
28644  // this face element's additional values,
28646  {
28648  new std::map<unsigned, unsigned>;
28649  }
28650 
28651  // Get pointer to the map
28652  std::map<unsigned, unsigned>* map_pt=
28654 
28655  // The id of the face to which this node belong in the bulk
28656  // element
28657  const unsigned id_face = 0;
28658  // We only resize the node values Vector if we haven't done it yet
28659  std::map<unsigned, unsigned>::const_iterator p=map_pt->find(id_face);
28660 
28661  // If this node hasn't been resized for current id
28662  if(p==map_pt->end())
28663  {
28664  // assign the face element id and the position of the
28665  //first entry to the boundary node
28666  (*map_pt)[id_face] = n_new_val;
28667 
28668  // resize the node vector of values
28669  new_nod_pt->resize(n_val);
28670  }
28671 
28672  } // if (n_val>n_new_val)
28673 
28674  } // if (!found_node_in_other_shared_boundaries ||
28675  // !found_on_haloed_element_with_other_processor)
28676 
28677  // Is the new node a SolidNode?
28678  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(new_nod_pt);
28679  if (solid_nod_pt!=0)
28680  {
28681  unsigned n_solid_val=solid_nod_pt->variable_position_pt()->nvalue();
28682  for (unsigned i_val=0;i_val<n_solid_val;i_val++)
28683  {
28684  for (unsigned t=0;t<n_prev;t++)
28685  {
28686  double read_data =
28688 
28689  // Check if necessary to state all the info. to the node if
28690  // it has been already found in shared boundaries with other
28691  // processors or in the haloed elements with of other
28692  // processors with the iproc processor
28693  if (!found_node_in_other_shared_boundaries ||
28694  !found_on_haloed_element_with_other_processor)
28695  {
28696  solid_nod_pt->variable_position_pt()->
28697  set_value(t, i_val, read_data);
28698  } // if (!found_node_in_other_shared_boundaries ||
28699  // !found_on_haloed_element_with_other_processor)
28700 
28701  }
28702 
28703  }
28704 
28705 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28707  << " Number of values solid node: "
28709  << std::endl;
28710 #endif
28711  const unsigned nvalues_solid_node =
28713  Vector<double> values_solid_node(nvalues_solid_node);
28714  for (unsigned i = 0; i < nvalues_solid_node; i++)
28715  {
28716  values_solid_node[i] =
28718  }
28719 
28720  // Check if necessary to state all the info. to the node if it
28721  // has been already found in shared boundaries with other
28722  // processors or in the haloed elements with of other processors
28723  // with the iproc processor
28724  if (!found_node_in_other_shared_boundaries ||
28725  !found_on_haloed_element_with_other_processor)
28726  {
28727  unsigned index = 0;
28728  solid_nod_pt->read_values_from_vector(values_solid_node, index);
28729  } // if (!found_node_in_other_shared_boundaries ||
28730  // !found_on_haloed_element_with_other_processor)
28731 
28732  }
28733 
28734  // Get copied history values
28735  // unsigned n_val=new_nod_pt->nvalue();
28736  for (unsigned i_val=0;i_val<n_val;i_val++)
28737  {
28738  for (unsigned t=0;t<n_prev;t++)
28739  {
28740  double read_data =
28742 
28743  // Check if necessary to state all the info. to the node if it
28744  // has been already found in shared boundaries with other
28745  // processors or in the haloed elements with of other
28746  // processors with the iproc processor
28747  if (!found_node_in_other_shared_boundaries ||
28748  !found_on_haloed_element_with_other_processor)
28749  {
28750  new_nod_pt->set_value(t, i_val, read_data);
28751  } // if (!found_node_in_other_shared_boundaries ||
28752  // !found_on_haloed_element_with_other_processor)
28753 
28754  }
28755 
28756  }
28757 
28758  // Get copied history values for positions
28759  unsigned n_dim=new_nod_pt->ndim();
28760  for (unsigned idim=0;idim<n_dim;idim++)
28761  {
28762  for (unsigned t=0;t<n_prev;t++)
28763  {
28764  double read_data =
28766 
28767  // Check if necessary to state all the info. to the node if it
28768  // has been already found in shared boundaries with other
28769  // processors or in the haloed elements with of other
28770  // processors with the iproc processor
28771  if (!found_node_in_other_shared_boundaries ||
28772  !found_on_haloed_element_with_other_processor)
28773  {
28774  // Copy to coordinate
28775  new_nod_pt->x(t,idim) = read_data;
28776 // DEBP(new_nod_pt->x(t,idim));
28777  } // if (!found_node_in_other_shared_boundaries ||
28778  // !found_on_haloed_element_with_other_processor)
28779  }
28780  }
28781 
28782  } // if (is_node_on_shared_boundary != 1)
28783 
28784  // If the node was not found in other shared boundaries (possibly
28785  // because it is the first time the node has been sent) then copy
28786  // the node to the shared boundaries where it should be, use the
28787  // special container for this cases
28788  if (n_shd_bnd_with_other_procs_have_node > 0 && // The node is on
28789  // shared
28790  // boundaries with
28791  // other processors
28792  !found_node_in_other_shared_boundaries) // The node has not
28793  // been previously
28794  // set as with
28795  // shared with
28796  // other processors
28797  // (first time)
28798  {
28799 
28800  // Update the node pointer in all the references of the node
28801  this->update_other_proc_shd_bnd_node_helper(new_nod_pt,
28802  other_proc_shd_bnd_node_pt,
28803  other_processor_1,
28804  other_processor_2,
28805  other_shared_boundaries,
28806  other_indexes,
28807  global_node_names,
28808  node_name_to_global_index,
28809  global_shared_node_pt);
28810 
28811  } // if (!found_node_in_other_shared_boundaries)
28812 
28813  }
28814 
28815 #endif // #ifdef OOMPH_HAS_MPI
28816 
28817  //======================================================================
28818  /// \short Get the nodes on the boundary (b), these are stored in the
28819  /// segment they belong (also used by the load balance method to
28820  /// re-set the number of segments per boundary after load balance has
28821  /// taken place)
28822  //======================================================================
28823  template <class ELEMENT>
28825  const unsigned &b, Vector<Vector<Node*> > &tmp_segment_nodes)
28826  {
28827  // Clear the data structure were to return the nodes
28828  tmp_segment_nodes.clear();
28829 
28830  // Temporary storage for face elements
28831  Vector<FiniteElement*> face_el_pt;
28832 
28833  // Temporary storage for number of elements adjacent to the boundary
28834  unsigned nel = 0;
28835 
28836  // Temporary storage for elements adjacent to the boundary that have
28837  // a common edge (related with internal boundaries)
28838  unsigned n_repeated_ele = 0;
28839 
28840  // Get the number of regions
28841  const unsigned n_regions = this->nregion();
28842 
28843  // Temporary storage for already visited pair of nodes (edges)
28844  Vector < std::pair<Node*, Node *> > done_nodes_pt;
28845 
28846  // Are there more than one region?
28847  if (n_regions > 1)
28848  {
28849  for (unsigned rr = 0 ; rr < n_regions; rr++)
28850  {
28851  const unsigned region_id =
28852  static_cast<unsigned>(this->Region_attribute[rr]);
28853 
28854  // Loop over all elements on boundaries in region rr
28855  const unsigned nel_in_region =
28856  this->nboundary_element_in_region(b, region_id);
28857 
28858  // Number of repeated element in region
28859  unsigned nel_repeated_in_region = 0;
28860 
28861  // Only bother to do anything else, if there are elements
28862  // associated with the boundary and the current region
28863  if (nel_in_region > 0)
28864  {
28865  // Flag that activates when a repeated face element is found,
28866  // possibly because we are dealing with an internal boundary
28867  bool repeated = false;
28868 
28869  // Loop over the bulk elements adjacent to boundary b
28870  for (unsigned e = 0; e < nel_in_region; e++)
28871  {
28872  // Get pointer to the bulk element that is adjacent to boundary b
28873  FiniteElement* bulk_elem_pt =
28874  this->boundary_element_in_region_pt(b, region_id, e);
28875 
28876 #ifdef OOMPH_HAS_MPI
28877  // In a distributed mesh only work with nonhalo elements
28878  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
28879  {
28880  // Increase the number of repeated elements
28881  n_repeated_ele++;
28882  // Go for the next element
28883  continue;
28884  }
28885 #endif
28886 
28887  //Find the index of the face of element e along boundary b
28888  int face_index =
28889  this->face_index_at_boundary_in_region(b, region_id, e);
28890 
28891  // Before adding the new element we need to be sure that the
28892  // edge that this element represents has not been already
28893  // added
28894  FiniteElement* tmp_ele_pt = new DummyFaceElement<ELEMENT> (
28895  bulk_elem_pt, face_index);
28896 
28897  // Number of nodes in the face element
28898  const unsigned n_nodes = tmp_ele_pt->nnode();
28899 
28900  std::pair<Node*, Node*> tmp_pair =
28901  std::make_pair(tmp_ele_pt->node_pt(0),
28902  tmp_ele_pt->node_pt(n_nodes - 1));
28903 
28904  std::pair<Node*, Node*> tmp_pair_inverse =
28905  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
28906  tmp_ele_pt->node_pt(0));
28907 
28908  // Search for repeated nodes
28909  unsigned n_done_nodes = done_nodes_pt.size();
28910  for (unsigned l = 0; l < n_done_nodes; l++)
28911  {
28912  if (tmp_pair == done_nodes_pt[l] || tmp_pair_inverse
28913  == done_nodes_pt[l])
28914  {
28915  nel_repeated_in_region++;
28916  repeated = true;
28917  break;
28918  }
28919 
28920  } // for (l < n_done_nodes)
28921 
28922  // Create new face element?
28923  if (!repeated)
28924  {
28925  // Add the pair of nodes (edge) to the node dones
28926  done_nodes_pt.push_back(tmp_pair);
28927  // Add the face element to the storage
28928  face_el_pt.push_back(tmp_ele_pt);
28929  }
28930  else
28931  {
28932  // Clean up
28933  delete tmp_ele_pt;
28934  tmp_ele_pt = 0;
28935  }
28936 
28937  // Re-start
28938  repeated = false;
28939 
28940  } // for (e < nel_in_region)
28941 
28942  // Add on the number of elements in the boundary with the
28943  // current region
28944  nel += nel_in_region;
28945 
28946  // Add on the number of repeated elements
28947  n_repeated_ele += nel_repeated_in_region;
28948 
28949  } // if (nel_in_region > 0)
28950 
28951  } // for (rr < n_regions)
28952 
28953  } // if (n_regions > 1)
28954  //Otherwise it's just the normal boundary functions
28955  else
28956  {
28957  // Assign the number of boundary elements
28958  nel = this->nboundary_element(b);
28959 
28960  //Only bother to do anything else, if there are elements
28961  if (nel > 0)
28962  {
28963  // Flag that activates when a repeated face element is found,
28964  // possibly because we are dealing with an internal boundary
28965  bool repeated = false;
28966 
28967  // Loop over the bulk elements adjacent to boundary b
28968  for (unsigned e = 0; e < nel; e++)
28969  {
28970  // Get pointer to the bulk element that is adjacent to boundary b
28971  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
28972 
28973 #ifdef OOMPH_HAS_MPI
28974  // In a distributed mesh only work with nonhalo elements
28975  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
28976  {
28977  // Increase the number of repeated elements
28978  n_repeated_ele++;
28979  // Go for the next element
28980  continue;
28981  }
28982 #endif
28983 
28984  //Find the index of the face of element e along boundary b
28985  int face_index = this->face_index_at_boundary(b, e);
28986 
28987  // Before adding the new element we need to be sure that the
28988  // edge that this element represent has not been already added
28989  FiniteElement* tmp_ele_pt = new DummyFaceElement<ELEMENT> (
28990  bulk_elem_pt, face_index);
28991 
28992  // Number of nodes in the face element
28993  const unsigned n_nodes = tmp_ele_pt->nnode();
28994 
28995  std::pair<Node*, Node*> tmp_pair =
28996  std::make_pair(tmp_ele_pt->node_pt(0),
28997  tmp_ele_pt->node_pt(n_nodes - 1));
28998 
28999  std::pair<Node*, Node*> tmp_pair_inverse =
29000  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
29001  tmp_ele_pt->node_pt(0));
29002 
29003  // Search for repeated nodes
29004  unsigned n_done_nodes = done_nodes_pt.size();
29005  for (unsigned l = 0; l < n_done_nodes; l++)
29006  {
29007  if (tmp_pair == done_nodes_pt[l] || tmp_pair_inverse
29008  == done_nodes_pt[l])
29009  {
29010  n_repeated_ele++;
29011  repeated = true;
29012  break;
29013  }
29014 
29015  } // for (l < n_done_nodes)
29016 
29017  // Create new face element
29018  if (!repeated)
29019  {
29020  // Add the pair of nodes (edge) to the node dones
29021  done_nodes_pt.push_back(tmp_pair);
29022  // Add the face element to the storage
29023  face_el_pt.push_back(tmp_ele_pt);
29024  }
29025  else
29026  {
29027  // Free the repeated bulk element!!
29028  delete tmp_ele_pt;
29029  tmp_ele_pt = 0;
29030  }
29031 
29032  // Re-start
29033  repeated = false;
29034 
29035  } // for (e < nel)
29036 
29037  } // if (nel > 0)
29038 
29039  } // else if (n_regions > 1)
29040 
29041  // Substract the repeated elements
29042  nel -= n_repeated_ele;
29043 
29044 #ifdef PARANOID
29045  if (nel!=face_el_pt.size())
29046  {
29047  std::ostringstream error_message;
29048  error_message
29049  << "The independet counting of face elements ("<<nel<<") for "
29050  << "boundary ("<<b<<") is different\n"
29051  << "from the real number of face elements in the container ("
29052  << face_el_pt.size() <<")\n";
29053  throw OomphLibError(error_message.str(),
29054  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29055  OOMPH_EXCEPTION_LOCATION);
29056  }
29057 #endif
29058 
29059  //Only bother to do anything else, if there are elements
29060  if (nel > 0)
29061  {
29062  // Assign the number of nonhalo face elements
29063  const unsigned nnon_halo_face_elements = nel;
29064 
29065  // The vector of list to store the "segments" that compound the
29066  // boundary (segments may appear only in a distributed mesh)
29067  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
29068 
29069  // Number of already sorted face elements (only nonhalo face
29070  // elements for a distributed mesh)
29071  unsigned nsorted_face_elements = 0;
29072 
29073  // Keep track of who's done (in a distributed mesh this apply to
29074  // nonhalo only)
29075  std::map<FiniteElement*, bool> done_ele;
29076 
29077  // Keep track of which element is inverted (in distributed mesh
29078  // the elements may be inverted with respect to the segment they
29079  // belong)
29080  std::map<FiniteElement*, bool> is_inverted;
29081 
29082  // Iterate until all possible segments have been created. In a non
29083  // distributed mesh there is only one segment which defines the
29084  // complete boundary
29085  while(nsorted_face_elements < nnon_halo_face_elements)
29086  {
29087  // The ordered list of face elements (in a distributed mesh a
29088  // collection of continuous face elements define a segment)
29089  std::list<FiniteElement*> sorted_el_pt;
29090 
29091 #ifdef PARANOID
29092  // Select an initial element for the segment
29093  bool found_initial_face_element = false;
29094 #endif
29095 
29096  FiniteElement* ele_face_pt = 0;
29097 
29098  unsigned iface = 0;
29099 #ifdef OOMPH_HAS_MPI
29100  if (this->is_mesh_distributed())
29101  {
29102  for (iface = 0; iface < nel; iface++)
29103  {
29104  ele_face_pt = face_el_pt[iface];
29105  // If not done then take it as initial face element
29106  if (!done_ele[ele_face_pt])
29107  {
29108 #ifdef PARANOID
29109  // Set the flag to indicate the initial element was
29110  // found
29111  found_initial_face_element = true;
29112 #endif
29113  // Increase the number of sorted face elements
29114  nsorted_face_elements++;
29115  // Set the index to the next face element
29116  iface++;
29117  // Add the face element in the container
29118  sorted_el_pt.push_back(ele_face_pt);
29119  // Mark as done
29120  done_ele[ele_face_pt] = true;
29121  break;
29122  } // if (!done_el[ele_face_pt])
29123  } // for (iface < nel)
29124  } // if (this->is_mesh_distributed())
29125  else
29126  {
29127 #endif // #ifdef OOMPH_HAS_MPI
29128 
29129  // When the mesh is not distributed just take the first
29130  // element and put it in the ordered list
29131  ele_face_pt = face_el_pt[0];
29132 #ifdef PARANOID
29133  // Set the flag to indicate the initial element was found
29134  found_initial_face_element = true;
29135 #endif
29136  // Increase the number of sorted face elements
29137  nsorted_face_elements++;
29138  // Set the index to the next face element
29139  iface = 1;
29140  // Add the face element in the container
29141  sorted_el_pt.push_back(ele_face_pt);
29142  // Mark as done
29143  done_ele[ele_face_pt] = true;
29144 #ifdef OOMPH_HAS_MPI
29145  } // else if (this->is_mesh_distributed())
29146 #endif
29147 
29148 #ifdef PARANOID
29149  if (!found_initial_face_element)
29150  {
29151  std::ostringstream error_message;
29152  error_message
29153  <<"Could not find an initial face element for the current segment\n";
29154  throw OomphLibError(error_message.str(),
29155  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29156  OOMPH_EXCEPTION_LOCATION);
29157  }
29158 #endif
29159 
29160  // Number of nodes in the face element
29161  const unsigned nnod = ele_face_pt->nnode();
29162 
29163  // Left and rightmost nodes (the left and right nodes of the
29164  // current face element)
29165  Node* left_node_pt = ele_face_pt->node_pt(0);
29166  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
29167 
29168  // Continue iterating if a new face element has been added to
29169  // the list
29170  bool face_element_added = false;
29171 
29172  // While a new face element has been added to the set of sorted
29173  // face elements continue iterating
29174  do
29175  {
29176  // Start from the next face element since we have already
29177  // added the previous one as the initial face element (any
29178  // previous face element had to be added on previous
29179  // iterations)
29180  for (unsigned iiface=iface;iiface<nel;iiface++)
29181  {
29182  // Re-start flag
29183  face_element_added = false;
29184 
29185  // Get the candidate element
29186  ele_face_pt = face_el_pt[iiface];
29187 
29188  // Check that the candidate element has not been done and is
29189  // not a halo element
29190  if (!done_ele[ele_face_pt])
29191  {
29192  // Get the left and right nodes of the current element
29193  Node* local_left_node_pt = ele_face_pt->node_pt(0);
29194  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
29195 
29196  // New element fits at the left of segment and is not inverted
29197  if (left_node_pt == local_right_node_pt)
29198  {
29199  left_node_pt = local_left_node_pt;
29200  sorted_el_pt.push_front(ele_face_pt);
29201  is_inverted[ele_face_pt] = false;
29202  face_element_added = true;
29203  }
29204  // New element fits at the left of segment and is inverted
29205  else if (left_node_pt == local_left_node_pt)
29206  {
29207  left_node_pt = local_right_node_pt;
29208  sorted_el_pt.push_front(ele_face_pt);
29209  is_inverted[ele_face_pt] = true;
29210  face_element_added = true;
29211  }
29212  // New element fits on the right of segment and is not inverted
29213  else if (right_node_pt == local_left_node_pt)
29214  {
29215  right_node_pt = local_right_node_pt;
29216  sorted_el_pt.push_back(ele_face_pt);
29217  is_inverted[ele_face_pt] = false;
29218  face_element_added = true;
29219  }
29220  // New element fits on the right of segment and is inverted
29221  else if (right_node_pt == local_right_node_pt)
29222  {
29223  right_node_pt = local_left_node_pt;
29224  sorted_el_pt.push_back(ele_face_pt);
29225  is_inverted[ele_face_pt] = true;
29226  face_element_added = true;
29227  }
29228 
29229  if (face_element_added)
29230  {
29231  // Mark the face element as done
29232  done_ele[ele_face_pt] = true;
29233  nsorted_face_elements++;
29234  break;
29235  }
29236 
29237  } // if (!done_el[ele_face_pt])
29238 
29239  } // for (iiface<nnon_halo_face_element)
29240 
29241  }while(face_element_added &&
29242  (nsorted_face_elements < nnon_halo_face_elements));
29243 
29244  // Store the created segment in the vector of segments
29245  segment_sorted_ele_pt.push_back(sorted_el_pt);
29246 
29247  } // while(nsorted_face_elements < nnon_halo_face_elements);
29248 
29249  // The number of boundary segments in this processor
29250  const unsigned nsegments = segment_sorted_ele_pt.size();
29251 
29252 #ifdef PARANOID
29253  if (nnon_halo_face_elements > 0 && nsegments == 0)
29254  {
29255  std::ostringstream error_message;
29256  error_message
29257  << "The number of segments is zero, but the number of nonhalo\n"
29258  << "elements is: (" << nnon_halo_face_elements << ")\n";
29259  throw OomphLibError(error_message.str(),
29260  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29261  OOMPH_EXCEPTION_LOCATION);
29262  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
29263 #endif
29264 
29265  // Go through all the segments, visit each face element in order
29266  // and get the nodes based that represent the boundary segment
29267 
29268  // Resize the container to store the nodes with the required
29269  // number of segments
29270  tmp_segment_nodes.resize(nsegments);
29271 
29272  for (unsigned is = 0; is < nsegments; is++)
29273  {
29274 #ifdef PARANOID
29275  if (segment_sorted_ele_pt[is].size() == 0)
29276  {
29277  std::ostringstream error_message;
29278  error_message
29279  << "The (" << is << ")-th segment has no elements\n";
29280  throw OomphLibError(error_message.str(),
29281  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29282  OOMPH_EXCEPTION_LOCATION);
29283  } // if (segment_sorted_ele_pt[is].size() == 0)
29284 #endif
29285 
29286  // Get access to the first element on the segment
29287  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
29288 
29289  // Number of nodes
29290  const unsigned nnod = first_ele_pt->nnode();
29291 
29292  // Get the first node of the current segment
29293  Node *first_node_pt = first_ele_pt->node_pt(0);
29294  if (is_inverted[first_ele_pt])
29295  {
29296  first_node_pt = first_ele_pt->node_pt(nnod-1);
29297  }
29298 
29299  // Add the node to the corresponding segment
29300  tmp_segment_nodes[is].push_back(first_node_pt);
29301 
29302  // Now loop over face elements in order to get the nodes
29303  for (std::list<FiniteElement*>::iterator it =
29304  segment_sorted_ele_pt[is].begin();
29305  it != segment_sorted_ele_pt[is].end(); it++)
29306  {
29307  // Get element
29308  FiniteElement* ele_pt = *it;
29309 
29310  // The last node pointer
29311  Node* last_node_pt = 0;
29312 
29313  // Get the last node
29314  if (!is_inverted[ele_pt])
29315  {
29316  last_node_pt = ele_pt->node_pt(nnod-1);
29317  }
29318  else
29319  {
29320  last_node_pt = ele_pt->node_pt(0);
29321  }
29322 
29323  // Add the node to the corresponding segment
29324  tmp_segment_nodes[is].push_back(last_node_pt);
29325 
29326  } // iterator over the elements in the segment
29327 
29328  } // for (is < nsegments)
29329 
29330  } // for (if (nel > 0))
29331 
29332  // Free memory allocation
29333  for (unsigned e = 0; e < nel; e++)
29334  {
29335  delete face_el_pt[e];
29336  face_el_pt[e] = 0;
29337  } // for (e < nel)
29338 
29339  }
29340 
29341 //======================================================================
29342 /// Adapt problem based on specified elemental error estimates
29343 /// This function implement serial and parallel mesh adaptation, the
29344 /// sections for parallel mesh adaptation are clearly identified by
29345 /// checking whether the mesh is distributed or not
29346 //======================================================================
29347  template <class ELEMENT>
29349  const Vector<double>& elem_error)
29350  {
29351  double t_start_overall=TimingHelpers::timer();
29352 
29353  // ==============================================================
29354  // BEGIN: Compute target areas
29355  // ==============================================================
29356 
29357  // Get refinement targets
29358  Vector<double> target_area(elem_error.size());
29359  double min_angle=compute_area_target(elem_error,
29360  target_area);
29361 
29362  // Post-process to allow only quantised target areas
29363  // in an attempt to more closely mimick the structured
29364  // case and limit the diffusion of small elements.
29365  bool quantised_areas=true;
29366  if (quantised_areas)
29367  {
29368  unsigned n=target_area.size();
29369  double total_area=0;
29370  // If the mesh is distributed then we need to get the contribution
29371  // of all processors to compute the total areas
29372  // ------------------------------------------
29373  // DISTRIBUTED MESH: BEGIN
29374  // ------------------------------------------
29375 #ifdef OOMPH_HAS_MPI
29376  if (this->is_mesh_distributed())
29377  {
29378  // When working in parallel we get the total area from the sum
29379  // of the the sub-areas of all the meshes
29380  double sub_area = 0.0;
29381 
29382  // Only add the area of nonhalo elements
29383  for (unsigned e=0;e<n;e++)
29384  {
29385  // Get the pointer to the element
29386  FiniteElement* ele_pt = this->finite_element_pt(e);
29387  if (!ele_pt->is_halo())
29388  {
29389  sub_area+=ele_pt->size();
29390  }
29391  } // for (e<n)
29392 
29393  // Get the communicator of the mesh
29394  OomphCommunicator* comm_pt = this->communicator_pt();
29395 
29396  // Get the total area
29397  MPI_Allreduce(&sub_area, &total_area, 1, MPI_DOUBLE, MPI_SUM,
29398  comm_pt->mpi_comm());
29399  }
29400  else
29401  {
29402  for (unsigned e=0;e<n;e++)
29403  {
29404  total_area+=this->finite_element_pt(e)->size();
29405  }
29406  }
29407  // ------------------------------------------
29408  // DISTRIBUTED MESH: END
29409  // ------------------------------------------
29410 #else // #ifdef OOMPH_HAS_MPI
29411  for (unsigned e=0;e<n;e++)
29412  {
29413  total_area+=this->finite_element_pt(e)->size();
29414  }
29415 #endif // #ifdef OOMPH_HAS_MPI
29416 
29417  for (unsigned e=0;e<n;e++)
29418  {
29419  unsigned level=
29420  unsigned(ceil(log(target_area[e]/total_area)/log(1.0/3.0)))-1;
29421  double new_target_area=total_area*pow(1.0/3.0,int(level));
29422  target_area[e]=new_target_area;
29423  }
29424 
29425  }
29426 
29427  // std::ofstream tmp;
29428  // tmp.open((Global_string_for_annotation:: String[0]+"overall_target_areas"+
29429  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
29430 
29431  // Get maximum target area
29432  unsigned n=target_area.size();
29433  double max_area=0.0;
29434  double min_area=DBL_MAX;
29435  for (unsigned e=0;e<n;e++)
29436  {
29437  if (target_area[e]>max_area) max_area=target_area[e];
29438  if (target_area[e]<min_area) min_area=target_area[e];
29439 
29440  // tmp << (finite_element_pt(e)->node_pt(0)->x(0)+
29441  // finite_element_pt(e)->node_pt(1)->x(0)+
29442  // finite_element_pt(e)->node_pt(2)->x(0))/3.0 << " "
29443  // << (finite_element_pt(e)->node_pt(0)->x(1)+
29444  // finite_element_pt(e)->node_pt(1)->x(1)+
29445  // finite_element_pt(e)->node_pt(2)->x(1))/3.0 << " "
29446  // << target_area[e] << " "
29447  // << finite_element_pt(e)->size() << " "
29448  // << elem_error[e] << " " << std::endl;
29449  }
29450 
29451  //tmp.close();
29452 
29453  oomph_info << "Maximum target area: " << max_area << std::endl;
29454  oomph_info << "Minimum target area: " << min_area << std::endl;
29455  oomph_info << "Number of elements to be refined: "
29456  << this->Nrefined << std::endl;
29457  oomph_info << "Number of elements to be unrefined: "
29458  << this->Nunrefined << std::endl;
29459  oomph_info << "Min. angle: " << min_angle << std::endl;
29460 
29461  double orig_max_area, orig_min_area;
29462  this->max_and_min_element_size(orig_max_area, orig_min_area);
29463  oomph_info << "Max./min. element size in original mesh: "
29464  << orig_max_area << " "
29465  << orig_min_area << std::endl;
29466 
29467  // ==============================================================
29468  // END: Compute target areas
29469  // ==============================================================
29470 
29471  // Check if boundaries need to be updated (regardless of
29472  // requirements of bulk error estimator) but don't do anything!
29473  bool check_only=true;
29474  bool outer_boundary_update_necessary= false;
29475  bool inner_boundary_update_necessary= false;
29476  bool inner_open_boundary_update_necessary=false;
29477 
29478  // Get the number of outer boundaries and check if they require
29479  // update
29480  const unsigned nouter=this->Outer_boundary_pt.size();
29481 
29482  if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29483  {
29484  // loop over the outer boundaries
29485  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29486  {
29487  outer_boundary_update_necessary=
29488  this->update_polygon_using_face_mesh(this->Outer_boundary_pt[i_outer],
29489  check_only);
29490  // Break the loop if at least one needs updating
29491  if (outer_boundary_update_necessary) break;
29492  }
29493 
29494  // Do not waste time if we already know that it is necessary an update
29495  // on the boundary representation
29496  if (!outer_boundary_update_necessary)
29497  {
29498  // Check if we need to generate a new 1D mesh representation of
29499  // the inner hole boundaries
29500  const unsigned nhole=this->Internal_polygon_pt.size();
29501  Vector<Vector<double> > internal_point_coord(nhole);
29502  inner_boundary_update_necessary=
29503  this->surface_remesh_for_inner_hole_boundaries(internal_point_coord,
29504  check_only);
29505 
29506  // If there was not necessary a change even on the internal closed
29507  // curve then finally check for the open curves as well
29508  if (!inner_boundary_update_necessary)
29509  {
29510  const unsigned n_open_polyline =
29511  this->Internal_open_curve_pt.size();
29512  // loop over the open polylines
29513  for (unsigned i = 0; i < n_open_polyline; i++)
29514  {
29515  inner_open_boundary_update_necessary=
29516  this->update_open_curve_using_face_mesh(
29517  this->Internal_open_curve_pt[i], check_only);
29518  // If at least one needs modification then break the for loop
29519  if (inner_open_boundary_update_necessary) break;
29520  }
29521  }
29522  }
29523  }
29524 
29525  // Flag to indicate whether we need to adapt or not (for parallel
29526  // mesh adaptation only)
29527  int adapt_all = 0;
29528  // ------------------------------------------
29529  // DISTRIBUTED MESH: BEGIN
29530  // ------------------------------------------
29531 #ifdef OOMPH_HAS_MPI
29532  // When working in distributed meshes we need to ensure that all the
29533  // processors take part on the adaptation process. If at least one
29534  // of the processors requires adaptation then all processor take
29535  // part on the adaptation process.
29536  int adapt_this_processor = 0;
29537  if (this->is_mesh_distributed())
29538  {
29539  // Do this processor requires adaptation?
29540  if ( (Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ||
29541  (min_angle < min_permitted_angle())
29542  || (outer_boundary_update_necessary)
29543  || (inner_boundary_update_necessary)
29544  || (inner_open_boundary_update_necessary) )
29545  {adapt_this_processor = 1;}
29546 
29547  // Get the communicator of the mesh
29548  OomphCommunicator* comm_pt = this->communicator_pt();
29549 
29550  // Verify if at least one processor needs mesh adaptation
29551  MPI_Allreduce(&adapt_this_processor, &adapt_all, 1, MPI_INT, MPI_SUM,
29552  comm_pt->mpi_comm());
29553  }
29554 #endif
29555  // ------------------------------------------
29556  // DISTRIBUTED MESH: END
29557  // ------------------------------------------
29558 
29559  // Should we bother to adapt?
29560  if ( (Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ||
29561  (min_angle < min_permitted_angle()) || (outer_boundary_update_necessary)
29562  || (inner_boundary_update_necessary)
29563  || (inner_open_boundary_update_necessary) || (adapt_all) )
29564  {
29565  if (! ( (Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ) )
29566  {
29567 
29568  if ( (outer_boundary_update_necessary)
29569  || (inner_boundary_update_necessary)
29570  || (inner_open_boundary_update_necessary) )
29571  {
29572  oomph_info
29573  << "Mesh regeneration triggered by inaccurate interface/surface\n"
29574  << "representation; setting Nrefined to number of elements.\n"
29575  << "outer_boundary_update_necessary : "
29576  << outer_boundary_update_necessary << "\n"
29577  << "inner_boundary_update_necessary : "
29578  << inner_boundary_update_necessary << "\n"
29579  << "inner_open_boundary_update_necessary: "
29580  << inner_open_boundary_update_necessary << "\n";
29581  Nrefined=nelement();
29582  }
29583  else
29584  {
29585  oomph_info
29586  << "Mesh regeneration triggered by min angle criterion;\n"
29587  << "setting Nrefined to number of elements.\n";
29588  Nrefined=nelement();
29589  }
29590  }
29591 
29592  // ------------------------------------------
29593  // DISTRIBUTED MESH: BEGIN
29594  // ------------------------------------------
29595 #ifdef OOMPH_HAS_MPI
29596  else if (this->is_mesh_distributed() &&
29597  adapt_this_processor == 0 && adapt_all > 0)
29598  {
29599  oomph_info
29600  << "Mesh regeneration triggered by (" << adapt_all << ") processor(s) "
29601  << "that require(s)\n adaptation\n";
29602  }
29603 #endif
29604  // ------------------------------------------
29605  // DISTRIBUTED MESH: END
29606  // ------------------------------------------
29607 
29608  // ==============================================================
29609  // BEGIN: Updating of boundaries representation (unrefinement and
29610  // refinement of polylines)
29611  // ==============================================================
29612 
29613  // Add the initial and final vertices of the polylines that
29614  // present connections to a list of non-delete-able vertices. The
29615  // vertices where the connections are performed cannot be deleted
29616  add_vertices_for_non_deletion();
29617 
29618  // ------------------------------------------
29619  // DISTRIBUTED MESH: BEGIN
29620  // ------------------------------------------
29621 #ifdef OOMPH_HAS_MPI
29622  // Synchronise connections for shared boundaries among
29623  // processors. This is required since one of the processor may noy
29624  // know that some of its shared boundaries have connections, thus
29625  // the vertices receiving the connections cannot be deleted
29626  if (this->is_mesh_distributed())
29627  {
29628  synchronize_shared_boundary_connections();
29629  }
29630 #endif // #ifdef OOMPH_HAS_MPI
29631  // ------------------------------------------
29632  // DISTRIBUTED MESH: END
29633  // ------------------------------------------
29634 
29635  // Are we allowing automatic insertion of vertices on boundaries?
29636  // If YES then Triangle automatically insert points along
29637  // boundaries, if NOT, then points are inserted along the
29638  // boundaries based on the target areas of boundary elements. When
29639  // the mesh is distributed the automatic insertion of vertices by
29640  // Triangle along the boundaries is not allowed
29641  if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29642  {
29643  //Generate a new 1D mesh representation of the inner hole boundaries
29644  unsigned nhole=this->Internal_polygon_pt.size();
29645  Vector<Vector<double> > internal_point_coord(nhole);
29646  this->surface_remesh_for_inner_hole_boundaries(internal_point_coord);
29647 
29648  //Update the representation of the outer boundary
29649  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29650  {
29651  this->update_polygon_using_face_mesh(
29652  this->Outer_boundary_pt[i_outer]);
29653  }
29654 
29655  // After updating outer and internal closed boundaries it is also
29656  // necessary to update internal boundaries.
29657  unsigned n_open_polyline = this->Internal_open_curve_pt.size();
29658  for (unsigned i = 0; i < n_open_polyline; i++)
29659  {
29660  this->update_open_curve_using_face_mesh(
29661  this->Internal_open_curve_pt[i]);
29662  }
29663 
29664  }
29665  else
29666  {
29667  // Update the representation of the internal boundaries using
29668  // the element's target area
29669 
29670  // Get the number of interal polygons
29671  const unsigned ninternal=this->Internal_polygon_pt.size();
29672  for (unsigned i_internal = 0; i_internal < ninternal; i_internal++)
29673  {
29674  this->update_polygon_using_elements_area(
29675  this->Internal_polygon_pt[i_internal], target_area);
29676  }
29677 
29678  // Update the representation of the outer boundaries using the
29679  // element's target area
29680  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29681  {
29682  this->update_polygon_using_elements_area(
29683  this->Outer_boundary_pt[i_outer], target_area);
29684  }
29685 
29686  // Update the representation of the internal open boundaries
29687  // using the element's target areas
29688  const unsigned n_open_polyline = this->Internal_open_curve_pt.size();
29689  for (unsigned i = 0; i < n_open_polyline; i++)
29690  {
29691  this->update_open_curve_using_elements_area(
29692  this->Internal_open_curve_pt[i], target_area);
29693  }
29694 
29695  // ------------------------------------------
29696  // DISTRIBUTED MESH: BEGIN
29697  // ------------------------------------------
29698 
29699  // When working with a distributed mesh we require to update the
29700  // boundary representation of the shared boundaries, this is
29701  // based on the target areas of the elements adjaced to the
29702  // shared boundaries
29703 #ifdef OOMPH_HAS_MPI
29704  // Update shared boundaries if the mesh is distributed
29705  if (this->is_mesh_distributed())
29706  {
29707  // Get the rank of the current processor
29708  const unsigned my_rank = this->communicator_pt()->my_rank();
29709 
29710  // Get the number of shared curves
29711  const unsigned n_curves = this->nshared_boundary_curves(my_rank);
29712  // Loop over the shared curves in the current processor
29713  for (unsigned nc = 0; nc < n_curves; nc ++)
29714  {
29715  // Update the shared polyline
29716  this->update_shared_curve_using_elements_area(
29717  this->Shared_boundary_polyline_pt[my_rank][nc],//shared_curve,
29718  target_area);
29719  }
29720 
29721  } // if (this->is_mesh_distributed())
29722 #endif
29723 
29724  // ------------------------------------------
29725  // DISTRIBUTED MESH: END
29726  // ------------------------------------------
29727 
29728  } // else if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29729 
29730  // ==============================================================
29731  // END: Updating of boundaries representation (unrefinement and
29732  // refinement of polylines)
29733  // ==============================================================
29734 
29735  // ==============================================================
29736  // BEGIN: Reset boundary coordinates for boundaries with no
29737  // associated GeomObject
29738  // ==============================================================
29739 
29740  //If there is not a geometric object associated with the boundary
29741  //then reset the boundary coordinates so that the lengths are
29742  //consistent in the new mesh and the old mesh.
29743  const unsigned n_boundary = this->nboundary();
29744 
29745  const double t_start_first_stage_segments_connectivity =
29747 
29748  // ------------------------------------------
29749  // DISTRIBUTED MESH: BEGIN
29750  // ------------------------------------------
29751 #ifdef OOMPH_HAS_MPI
29752  // Clear storage for assignment of initial zeta values for
29753  // boundaries
29754  if (this->is_mesh_distributed())
29755  {
29756  this->Assigned_segments_initial_zeta_values.clear();
29757  }
29758 #endif // #ifdef OOMPH_HAS_MPI
29759  // ------------------------------------------
29760  // DISTRIBUTED MESH: END
29761  // ------------------------------------------
29762 
29763  // Loop over the boundaries to assign boundary coordinates
29764  for(unsigned b=0;b<n_boundary;++b)
29765  {
29766  // ------------------------------------------
29767  // DISTRIBUTED MESH: BEGIN
29768  // ------------------------------------------
29769 #ifdef OOMPH_HAS_MPI
29770  if (this->is_mesh_distributed())
29771  {
29772  // In a distributed mesh, the boundaries may have been split
29773  // across processors during the distribution process, thus we
29774  // need to compute the connectivity among the segments of the
29775  // boundary to correctly assign its boundary coordinates
29776  this->
29777  compute_boundary_segments_connectivity_and_initial_zeta_values(b);
29778  }
29779 #endif
29780  // ------------------------------------------
29781  // DISTRIBUTED MESH: END
29782  // ------------------------------------------
29783 
29784  // Does the boundary has an associated GeomObject
29785  if(this->boundary_geom_object_pt(b)==0)
29786  {
29787  this->template setup_boundary_coordinates<ELEMENT>(b);
29788  }
29789 
29790  // ------------------------------------------
29791  // DISTRIBUTED MESH: BEGIN
29792  // ------------------------------------------
29793 #ifdef OOMPH_HAS_MPI
29794  if (this->is_mesh_distributed())
29795  {
29796  // Synchronise boundary coordinates for internal open curves,
29797  // also establish the boundary coordinates for the nodes on
29798  // the corners of elements not on the boundary
29799  this->synchronize_boundary_coordinates(b);
29800  }
29801 #endif
29802  // ------------------------------------------
29803  // DISTRIBUTED MESH: END
29804  // ------------------------------------------
29805 
29806  } // for (b<n_boundary)
29807 
29808  const double t_total_first_stage_segments_connectivity =
29809  TimingHelpers::timer() - t_start_first_stage_segments_connectivity;
29810 
29811  // ==============================================================
29812  // END: Reset boundary coordinates for boundaries with no
29813  // associated GeomObject
29814  // ==============================================================
29815 
29816  // ------------------------------------------
29817  // DISTRIBUTED MESH: BEGIN
29818  // ------------------------------------------
29819 #ifdef OOMPH_HAS_MPI
29820  // ==============================================================
29821  // BEGIN: Create the new representation of the domain by joining
29822  // the original boundaries and the shared boundaries.
29823  // ==============================================================
29824 
29825  // Storage for the new temporary polygons "closed" by the shared
29826  // boundaries
29827  Vector<TriangleMeshPolygon *> tmp_outer_polygons_pt;
29828 
29829  // Storage for the new temporary open curves, could be the
29830  // original open curves or "chunks" of the original open curves
29831  // not overlapped by shared boundaries
29832  Vector<TriangleMeshOpenCurve *> tmp_open_curves_pt;
29833 
29834  if (this->is_mesh_distributed())
29835  {
29836  // Create the new polygons and open curves with help of the
29837  // original polylines and shared polylines
29838  this->create_distributed_domain_representation(tmp_outer_polygons_pt,
29839  tmp_open_curves_pt);
29840 
29841  // Create the connections of the temporary domain representations
29842  this->create_temporary_boundary_connections(tmp_outer_polygons_pt,
29843  tmp_open_curves_pt);
29844  }
29845  // ==============================================================
29846  // END: Create the new representation of the domain by joining
29847  // the original boundaries and the shared boundaries.
29848  // ==============================================================
29849 #endif
29850  // ------------------------------------------
29851  // DISTRIBUTED MESH: END
29852  // ------------------------------------------
29853 
29854  // Re-establish polylines' connections. The boundary
29855  // representation has changed (new polylines), therefore we need
29856  // to update the connection information
29857  Vector<TriangleMeshPolyLine*> resume_initial_connection_polyline_pt;
29858  Vector<TriangleMeshPolyLine*> resume_final_connection_polyline_pt;
29859  restore_boundary_connections(resume_initial_connection_polyline_pt,
29860  resume_final_connection_polyline_pt);
29861 
29862  // Update the region information by setting the coordinates from the
29863  // centroid of the first element in each region (which should allow
29864  // automatic updates when the regions deform)
29865  {
29866  unsigned n_region = this->nregion();
29867  if(n_region > 1)
29868  {
29869  for(std::map<unsigned, Vector<double> >::iterator it =
29870  this->Regions_coordinates.begin();
29871  it!=this->Regions_coordinates.end(); ++it)
29872  {
29873  //Storage for the approximate centroid
29874  Vector<double> centroid(2,0.0);
29875 
29876  //Get the region id
29877  unsigned region_id = it->first;
29878 
29879  //Report information
29880  oomph_info << "Region " << region_id << ": "
29881  << it->second[0] << " " << it->second[1] << " ";
29882 
29883  //Check that there is at least one element in the region
29884  unsigned n_region_element = this->nregion_element(region_id);
29885  if(n_region_element > 0)
29886  {
29887  //Cache pointer to the first element
29888  FiniteElement* const elem_pt = this->region_element_pt(region_id,0);
29889 
29890  //Loop over the corners of the triangle and average
29891  for(unsigned n=0;n<3;n++)
29892  {
29893  Node* const nod_pt = elem_pt->node_pt(n);
29894  for(unsigned i=0;i<2;i++) {centroid[i] += nod_pt->x(i);}
29895  }
29896  for(unsigned i=0;i<2;i++) {centroid[i] /= 3;}
29897  //Now we have the centroid set it
29898  it->second = centroid;
29899 
29900  oomph_info << " , " <<
29901  it->second[0] << " " << it->second[1] << std::endl;
29902  } //end of case when there is at least one element
29903 
29904  } // loop over regions coordinates
29905 
29906  } // if(n_region > 1)
29907 
29908  } // Updating region info.
29909 
29910  // ==============================================================
29911  // BEGIN: Create background mesh
29912  // ==============================================================
29913 
29914  // Are we dealing with a solid mesh?
29915  SolidMesh* solid_mesh_pt=dynamic_cast<SolidMesh*>(this);
29916 
29917  // Build temporary uniform background mesh
29918  //----------------------------------------
29919  // with area set by maximum required area
29920  //---------------------------------------
29921  RefineableTriangleMesh<ELEMENT>* tmp_new_mesh_pt=0;
29922 
29923  // The storage for the new temporary boundaries representation to
29924  // create the background mesh
29925  Vector<TriangleMeshClosedCurve*> closed_curve_pt;
29927  Vector<TriangleMeshOpenCurve*> open_curves_pt;
29928 
29929 #ifdef OOMPH_HAS_MPI
29930  if (!this->is_mesh_distributed())
29931 #endif
29932  {
29933  // Copy the outer boundaries
29934  closed_curve_pt.resize(nouter);
29935  for (unsigned i = 0; i < nouter; i++)
29936  {
29937  closed_curve_pt[i] = this->Outer_boundary_pt[i];
29938  }
29939 
29940  // Copy the internal closed boundaries (may be holes)
29941  const unsigned n_holes = this->Internal_polygon_pt.size();
29942  hole_pt.resize(n_holes);
29943  for (unsigned i = 0; i < n_holes; i++)
29944  {
29945  hole_pt[i] = this->Internal_polygon_pt[i];
29946  }
29947 
29948  // Copy the internal open curves
29949  const unsigned n_open_curves = this->Internal_open_curve_pt.size();
29950  open_curves_pt.resize(n_open_curves);
29951  for (unsigned i = 0; i < n_open_curves; i++)
29952  {
29953  open_curves_pt[i] = this->Internal_open_curve_pt[i];
29954  }
29955  }
29956  // ------------------------------------------
29957  // DISTRIBUTED MESH: BEGIN
29958  // ------------------------------------------
29959 #ifdef OOMPH_HAS_MPI
29960  else
29961  {
29962  // Copy the new representation of the outer/internal closed
29963  // boundaries
29964  const unsigned n_tmp_outer = tmp_outer_polygons_pt.size();
29965  closed_curve_pt.resize(n_tmp_outer);
29966  for (unsigned i = 0; i < n_tmp_outer; i++)
29967  {
29968  closed_curve_pt[i] = tmp_outer_polygons_pt[i];
29969  }
29970 
29971  // Copy the new representation of the internal open curves
29972  const unsigned n_open_curves = tmp_open_curves_pt.size();
29973  open_curves_pt.resize(n_open_curves);
29974  for (unsigned i = 0; i < n_open_curves; i++)
29975  {
29976  open_curves_pt[i] = tmp_open_curves_pt[i];
29977  }
29978 
29979  }
29980 #endif
29981  // ------------------------------------------
29982  // DISTRIBUTED MESH: END
29983  // ------------------------------------------
29984 
29985  // ----------------------------------------------------------------
29986  // Gather all the information and use the TriangleMeshParameters
29987  // object which help us on the manage of all TriangleMesh object's
29988  // information
29989 
29990  // Create the TriangleMeshParameters objects with the outer boundary
29991  // as the only one parameter
29992  TriangleMeshParameters triangle_mesh_parameters(closed_curve_pt);
29993 
29994  // Pass information about the holes
29995  triangle_mesh_parameters.internal_closed_curve_pt() = hole_pt;
29996 
29997  // Pass information about the internal open boundaries
29998  triangle_mesh_parameters.internal_open_curves_pt() = open_curves_pt;
29999 
30000  // Set the element area
30001  triangle_mesh_parameters.element_area() = max_area;
30002 
30003  // Pass information about the extra holes (not defined with closed
30004  // boundaries)
30005  triangle_mesh_parameters.extra_holes_coordinates() =
30006  this->Extra_holes_coordinates;
30007 
30008  //Pass information about regions
30009  triangle_mesh_parameters.regions_coordinates() =
30010  this->Regions_coordinates;
30011 
30012  //Pass information about the using of regions
30013  if (this->Use_attributes)
30014  {
30015  triangle_mesh_parameters.enable_use_attributes();
30016  }
30017 
30018  //Pass information about allowing the creation of new points
30019  if (!this->is_automatic_creation_of_vertices_on_boundaries_allowed())
30020  {
30021  triangle_mesh_parameters.disable_automatic_creation_of_vertices_on_boundaries();
30022  }
30023 
30024  // When the mesh is distributed we need to create a distributed
30025  // background mesh
30026 #ifdef OOMPH_HAS_MPI
30027  if (this->is_mesh_distributed())
30028  {
30029  // Mark the mesh to be created as distributed by passing a
30030  // pointer to the communicator
30031  triangle_mesh_parameters.set_communicator_pt(this->communicator_pt());
30032  }
30033 #endif
30034 
30035  // ----------------------------------------------------------
30036  // Build the background mesh using Triangle
30037  // ----------------------------------------------------------
30038  const double t_start_building_background_mesh =
30040 
30041  if (solid_mesh_pt!=0)
30042  {
30043  tmp_new_mesh_pt=new RefineableSolidTriangleMesh<ELEMENT>
30044  (triangle_mesh_parameters, this->Time_stepper_pt);
30045  }
30046  else
30047  {
30048  tmp_new_mesh_pt=new RefineableTriangleMesh<ELEMENT>
30049  (triangle_mesh_parameters, this->Time_stepper_pt);
30050  }
30051 
30052  if (Print_timings_level_adaptation>2)
30053  {
30054  oomph_info << "CPU for building background mesh: "
30055  <<TimingHelpers::timer()-t_start_building_background_mesh
30056  << std::endl;
30057  }
30058 
30059  // Pass the info. regarding the maximum and minimum element size
30060  // from the old mesh to the background mesh
30061  const double this_max_element_size = this->max_element_size();
30062  const double this_min_element_size = this->min_element_size();
30063  tmp_new_mesh_pt->max_element_size() = this_max_element_size;
30064  tmp_new_mesh_pt->min_element_size() = this_min_element_size;
30065 
30066  // ... also copy the minimum permitted angle
30067  const double this_min_permitted_angle = this->min_permitted_angle();
30068  tmp_new_mesh_pt->min_permitted_angle() = this_min_permitted_angle;
30069 
30070  // ------------------------------------------
30071  // DISTRIBUTED MESH: BEGIN
30072  // ------------------------------------------
30073 #ifdef OOMPH_HAS_MPI
30074  // If the mesh is distributed we need to pass and set the
30075  // information of internal boundaries overlaped by shared
30076  // boundaries
30077  if (this->is_mesh_distributed())
30078  {
30079  // Check if necessary to fill boundary elements for those
30080  // internal boundaries that overlap shared boundaries
30081  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30082  {
30083  // Copy the data structures that indicates which shared
30084  // boundaries are part of an internal boundary
30085  tmp_new_mesh_pt->shared_boundary_overlaps_internal_boundary() =
30086  this->shared_boundary_overlaps_internal_boundary();
30087 
30088  // Copy the data structure that indicates which are the shared
30089  // boundaries in each processor
30090  tmp_new_mesh_pt->shared_boundaries_ids() =
30091  this->shared_boundaries_ids();
30092 
30093  // Fill the structures for the boundary elements and face indexes
30094  // of the boundary elements
30095  tmp_new_mesh_pt->
30096  fill_boundary_elements_and_nodes_for_internal_boundaries();
30097 
30098  } // if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30099 
30100  } // if (this->is_mesh_distributed())
30101 #endif // #ifdef OOMPH_HAS_MPI
30102  // ------------------------------------------
30103  // DISTRIBUTED MESH: END
30104  // ------------------------------------------
30105 
30106  // Snap to curvilinear boundaries (some code duplication as this
30107  // is repeated below but helper function would take so many
30108  // arguments that it's nearly as messy...
30109 
30110  //Pass the boundary geometric objects to the new mesh
30111  tmp_new_mesh_pt->boundary_geom_object_pt() =
30112  this->boundary_geom_object_pt();
30113 
30114  //Reset the boundary coordinates if there is
30115  //a geometric object associated with the boundary
30116  tmp_new_mesh_pt->boundary_coordinate_limits() =
30117  this->boundary_coordinate_limits();
30118 
30119  const double t_start_second_stage_segments_connectivity =
30121 
30122  for (unsigned b=0;b<n_boundary;b++)
30123  {
30124  // ------------------------------------------
30125  // DISTRIBUTED MESH: BEGIN
30126  // ------------------------------------------
30127 #ifdef OOMPH_HAS_MPI
30128  if (this->is_mesh_distributed())
30129  {
30130  // Identify the segments of the new mesh with the ones of the
30131  // original mesh
30132  tmp_new_mesh_pt->
30133  identify_boundary_segments_and_assign_initial_zeta_values(b,this);
30134  }
30135 #endif
30136  // ------------------------------------------
30137  // DISTRIBUTED MESH: END
30138  // ------------------------------------------
30139 
30140  // Setup boundary coordinates for boundaries with GeomObject
30141  // associated
30142  if(tmp_new_mesh_pt->boundary_geom_object_pt(b)!=0)
30143  {
30144  tmp_new_mesh_pt->template setup_boundary_coordinates<ELEMENT>(b);
30145  }
30146 
30147  }
30148 
30149  const double t_total_second_stage_segments_connectivity =
30150  TimingHelpers::timer() - t_start_second_stage_segments_connectivity;
30151 
30152  const double t_start_snap_nodes_bg_mesh=TimingHelpers::timer();
30153  //Move the nodes on the new boundary onto the old curvilinear
30154  //boundary. If the boundary is straight this will do precisely
30155  //nothing but will be somewhat inefficient
30156  for(unsigned b=0;b<n_boundary;b++)
30157  {
30158  this->snap_nodes_onto_boundary(tmp_new_mesh_pt,b);
30159  }
30160 
30161  const double t_total_snap_nodes_bg_mesh=
30162  TimingHelpers::timer()-t_start_snap_nodes_bg_mesh;
30163 
30164  if (Print_timings_level_adaptation>2)
30165  {
30166  oomph_info<< "CPU for snapping nodes onto boundaries "
30167  << "(background mesh): "
30168  << t_total_snap_nodes_bg_mesh << std::endl;
30169  }
30170 
30171  // Update mesh further?
30172  if(Mesh_update_fct_pt!=0)
30173  {
30174  Mesh_update_fct_pt(tmp_new_mesh_pt);
30175  }
30176 
30177  //If we have a continuation problem
30178  //any problem in which the timestepper is a "generalisedtimestepper",
30179  //which will have been set by the problem, then ensure
30180  //all data in the new mesh has the appropriate timestepper
30181  /*if(dynamic_cast<GeneralisedTimeStepper*>(this->Time_stepper_pt))
30182  {
30183  tmp_new_mesh_pt->set_nodal_and_elemental_time_stepper(
30184  this->Time_stepper_pt);
30185  tmp_new_mesh_pt->set_mesh_level_time_stepper(this->Time_stepper_pt);
30186  }*/
30187 
30188 
30189  //tmp_new_mesh_pt->output("mesh_nodes_snapped_0.dat");
30190  //this->output("existing_mesh.dat");
30191 
30192  // ==============================================================
30193  // END: Create background mesh
30194  // ==============================================================
30195 
30196  // ==============================================================
30197  // BEGIN: Transferring of target areas and creation of new mesh
30198  // ==============================================================
30199 
30200  // Get the TriangulateIO object associated with that mesh
30201  TriangulateIO tmp_new_triangulateio =
30202  tmp_new_mesh_pt->triangulateio_representation();
30203  RefineableTriangleMesh<ELEMENT>* new_mesh_pt = 0;
30204 
30205  // If the mesh is a solid mesh then do the mapping based on the
30206  // Eulerian coordinates
30207  bool use_eulerian_coords=false;
30208  if (solid_mesh_pt!=0)
30209  {
30210  use_eulerian_coords=true;
30211  }
30212 
30213 
30214 #ifdef OOMPH_HAS_CGAL
30215 
30216  // Make cgal-based bin
30217  CGALSamplePointContainerParameters cgal_params(this);
30218  if (use_eulerian_coords)
30219  {
30221  }
30222  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(&cgal_params);
30223 
30224 #else
30225 
30226  // Make nonrefineable bin
30227  NonRefineableBinArrayParameters params(this);
30228  if (use_eulerian_coords)
30229  {
30231  }
30232  Vector<unsigned> bin_dim(2);
30233  bin_dim[0]=Nbin_x_for_area_transfer;
30234  bin_dim[1]=Nbin_y_for_area_transfer;
30235  params.dimensions_of_bin_array()=bin_dim;
30236  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(&params);
30237 
30238 #endif
30239 
30240  // Set up a map from pointer to element to its number
30241  // in the mesh
30242  std::map<GeneralisedElement*,unsigned> element_number;
30243  unsigned nelem=this->nelement();
30244  for (unsigned e=0;e<nelem;e++)
30245  {
30246  element_number[this->element_pt(e)]=e;
30247  }
30248 
30249 #ifndef OOMPH_HAS_CGAL
30250 
30251  // Create a vector to store the min target area of each bin (at
30252  // this stage the number of bins should not be that large, so it
30253  // should be safe to build a vector for the total number of bins)
30254  Vector<double> bin_min_target_area;
30255 
30256  // Get pointer to sample point container
30257  NonRefineableBinArray* bin_array_pt=
30258  dynamic_cast<NonRefineableBinArray*>(mesh_geom_obj_pt->
30259  sample_point_container_pt());
30260  if (bin_array_pt==0)
30261  {
30262  throw OomphLibError(
30263  "Sample point container has to be NonRefineableBinArray",
30264  OOMPH_CURRENT_FUNCTION,
30265  OOMPH_EXCEPTION_LOCATION);
30266  }
30267 
30268  {
30269  unsigned n_bin=0;
30270  unsigned max_n_entry=0;
30271  unsigned min_n_entry=UINT_MAX;
30272  unsigned tot_n_entry=0;
30273  unsigned n_empty=0;
30274  bin_array_pt->get_fill_stats(n_bin,max_n_entry,min_n_entry,
30275  tot_n_entry,n_empty);
30276 
30277  oomph_info << "Before bin diffusion:"
30278  << " nbin:("<<n_bin<<")"
30279  << " nempty:("<<n_empty<<")"
30280  << " min:("<<min_n_entry<<")"
30281  << " max:("<<max_n_entry<<")"
30282  << " average entries:("
30283  << double(tot_n_entry)/double(n_bin)<<")"
30284  << std::endl;
30285  }
30286 
30287  // Fill bin by diffusion
30288  double t0_bin_diff=TimingHelpers::timer();
30289  oomph_info << "Going into diffusion bit...\n";
30290  bin_array_pt->fill_bin_by_diffusion();
30291  oomph_info << "Back from diffusion bit...\n";
30292  oomph_info << "Time for bin diffusion: "
30293  << TimingHelpers::timer()-t0_bin_diff
30294  << std::endl;
30295 
30296  // Do some stats
30297  {
30298  unsigned n_bin=0;
30299  unsigned max_n_entry=0;
30300  unsigned min_n_entry=UINT_MAX;
30301  unsigned tot_n_entry=0;
30302  unsigned n_empty=0;
30303  bin_array_pt->get_fill_stats(n_bin,max_n_entry,min_n_entry,
30304  tot_n_entry,n_empty);
30305 
30306  oomph_info << "After bin diffusion:"
30307  << " nbin:("<<n_bin<<")"
30308  << " nempty:("<<n_empty<<")"
30309  << " min:("<<min_n_entry<<")"
30310  << " max:("<<max_n_entry<<")"
30311  << " average entries:("
30312  << double(tot_n_entry)/double(n_bin)<<")"
30313  << std::endl;
30314  }
30315 
30316 
30317  // For each bin, compute the minimum of the target areas in the bin
30318 
30319  // Timing for map
30320  double t_total_map=0.0;
30321 
30322  // Counter for map
30323  unsigned counter_map = 0;
30324 
30325  // Get access to the bins (we need access to the content of the
30326  // bins to compute the minimum of the target areas of the elements
30327  // in each bin)
30328  const std::map<unsigned,Vector<std::pair<FiniteElement*,
30329  Vector<double> > > >*
30330  bins_pt=bin_array_pt->get_all_bins_content();
30331 
30332  // Get the number of bins
30333  const unsigned n_bin=bins_pt->size();
30334 
30335  // Create a vector to store the min target area of each bin (at
30336  // this stage the number of bins should not be that large, so it
30337  // should be safe to build a vector for the total number of bins)
30338  bin_min_target_area.resize(n_bin);
30339  for (unsigned u=0;u<n_bin;u++)
30340  {
30341  bin_min_target_area[u]=0.0;
30342  }
30343  // loop over the bins, get their elements and compute the minimum
30344  // target area of all of them
30345  typedef std::map<unsigned,
30346  Vector<std::pair<FiniteElement*,
30347  Vector<double> > > >::const_iterator IT;
30348  for (IT it=bins_pt->begin();it!=bins_pt->end();it++)
30349  {
30350  // The bin number
30351  unsigned ib=(*it).first;
30352 
30353  // Get the number of elements in the bin
30354  const unsigned n_ele_bin = (*it).second.size();
30355 
30356  // loop over the elements in the bin
30357  for (unsigned ee=0;ee<n_ele_bin;ee++)
30358  {
30359  // Get ee-th element (in currrent mesh) in ib-th bin
30360  GeneralisedElement* ele_pt=(*it).second[ee].first;
30361  double t_map=TimingHelpers::timer();
30362  const unsigned ele_number = element_number[ele_pt];
30363  t_total_map+=TimingHelpers::timer()-t_map;
30364 
30365  // Increase the number of calls to map
30366  counter_map++;
30367 
30368  // Go for smallest target area of any element in this bin to
30369  // force "one level" of refinement (the one-level-ness is
30370  // enforced below by limiting the actual reduction in area
30371  if (bin_min_target_area[ib]!=0)
30372  {
30373  bin_min_target_area[ib]=
30374  std::min(bin_min_target_area[ib], target_area[ele_number]);
30375  }
30376  else
30377  {
30378  bin_min_target_area[ib]=target_area[ele_number];
30379  }
30380 
30381  } // for (ee<n_ele_bin)
30382 
30383  } // for (it!=bins.end())
30384 
30385  oomph_info << "CPU for map[counter="<<counter_map<<"]: "
30386  << t_total_map << std::endl;
30387 
30388 
30389  // Optional output for debugging (keep it around!)
30390  const bool output_bins=false;
30391  if (output_bins)
30392  {
30393  unsigned length=bin_min_target_area.size();
30394  for (unsigned u = 0;u<length;u++)
30395  {
30396  oomph_info << "Bin n" << u << ",target area: "
30397  << bin_min_target_area[u]<<std::endl;
30398  }
30399  }
30400 
30401 #endif
30402 
30403 
30404  // Now start iterating to refine mesh recursively
30405  //-----------------------------------------------
30406  bool done=false;
30407  unsigned iter=0;
30408 #ifdef OOMPH_HAS_MPI
30409  // The number of elements that require (un)refinement
30410  unsigned n_ele_need_refinement = 0;
30411 #endif
30412 
30413  // The timing for the third stage of segments connectivity
30414  double t_total_third_stage_segments_connectivity = 0.0;
30415 
30416  // The timing for the transfering target areas
30417  double t_total_transfer_target_areas = 0.0;
30418 
30419  // The timing for the copying of target areas
30420  double t_total_limit_target_areas = 0.0;
30421 
30422  // The timing to create the new mesh
30423  double t_total_create_new_adapted_mesh = 0.0;
30424 
30425  // The timing for the snapping of the nodes on the new meshes
30426  double t_total_snap_nodes = 0.0;
30427 
30428  // The timing to check whether other processors need to adapt
30429  double t_total_wait_other_processors = 0.0;
30430  double t_iter=TimingHelpers::timer();
30431  while (!done)
30432  {
30433  // Accept by default but overwrite if things go wrong below
30434  done=true;
30435 
30436  double t_start_transfer_target_areas=TimingHelpers::timer();
30437  double t0_loop_int_pts=TimingHelpers::timer();
30438 
30439  // Loop over elements in new (tmp) mesh and visit all
30440  // its integration points. Check where it's located in the bin
30441  // structure of the current mesh and pass the target area
30442  // to the new element
30443  nelem=tmp_new_mesh_pt->nelement();
30444 
30445  // Store the target areas for elements in the temporary
30446  // TriangulateIO mesh
30447  Vector<double> new_transferred_target_area(nelem,0.0);
30448  for (unsigned e=0;e<nelem;e++)
30449  { // start loop el
30450  ELEMENT* el_pt=dynamic_cast<ELEMENT*>(tmp_new_mesh_pt->element_pt(e));
30451  unsigned nint=el_pt->integral_pt()->nweight();
30452  for (unsigned ipt=0;ipt<nint;ipt++)
30453  {
30454  // Get the coordinate of current point
30455  Vector<double> s(2);
30456  for(unsigned i=0;i<2;i++)
30457  {
30458  s[i] = el_pt->integral_pt()->knot(ipt,i);
30459  }
30460 
30461  Vector<double> x(2);
30462  el_pt->interpolated_x(s,x);
30463 
30464 #if OOMPH_HAS_CGAL
30465 
30466  // Try the five nearest sample points for Newton search
30467  // then just settle on the nearest one
30468  GeomObject* geom_obj_pt=0;
30469  unsigned max_sample_points=
30470  Max_sample_points_for_limited_locate_zeta_during_target_area_transfer;
30471  dynamic_cast<CGALSamplePointContainer*>(mesh_geom_obj_pt->
30472  sample_point_container_pt())->
30473  limited_locate_zeta(x,max_sample_points,
30474  geom_obj_pt,s);
30475 #ifdef PARANOID
30476  if (geom_obj_pt==0)
30477  {
30478  std::stringstream error_message;
30479  error_message
30480  << "Limited locate zeta failed for zeta = [ "
30481  << x[0] << " " << x[1] << " ]. Makes no sense!\n";
30482  throw OomphLibError(error_message.str(),
30483  OOMPH_CURRENT_FUNCTION,
30484  OOMPH_EXCEPTION_LOCATION);
30485  }
30486  else
30487  {
30488 #endif
30489  FiniteElement* fe_pt=dynamic_cast<FiniteElement*>(geom_obj_pt);
30490 #ifdef PARANOID
30491  if (fe_pt==0)
30492  {
30493  std::stringstream error_message;
30494  error_message
30495  << "Cast to FE for GeomObject returned by limited locate zeta failed for zeta = [ "
30496  << x[0] << " " << x[1] << " ]. Makes no sense!\n";
30497  throw OomphLibError(error_message.str(),
30498  OOMPH_CURRENT_FUNCTION,
30499  OOMPH_EXCEPTION_LOCATION);
30500  }
30501  else
30502  {
30503 #endif
30504  // What's the target area of the element that contains this point
30505  double tg_area=target_area[element_number[fe_pt]];
30506 
30507  // Go for smallest target area over all integration
30508  // points in new element
30509  // to force "one level" of refinement (the one-level-ness
30510  // is enforced below by limiting the actual reduction in
30511  // area
30512  if (new_transferred_target_area[e]!=0)
30513  {
30514  new_transferred_target_area[e]=
30515  std::min(new_transferred_target_area[e],
30516  tg_area);
30517  }
30518  else
30519  {
30520  new_transferred_target_area[e]=tg_area;
30521  }
30522 #ifdef PARANOID
30523  }
30524  }
30525 #endif
30526 
30527 #else
30528 
30529  // Find the bin that contains that point and its contents
30530  int bin_number=0;
30531  bin_array_pt->get_bin(x,bin_number);
30532 
30533  // Did we find it?
30534  if (bin_number<0)
30535  {
30536  // Not even within bin boundaries... odd
30537  std::stringstream error_message;
30538  error_message
30539  << "Very odd -- we're looking for a point[ "
30540  << x[0] << " " << x[1] << " ] that's not even \n"
30541  << "located within the bin boundaries.\n";
30542  throw OomphLibError(error_message.str(),
30543  "RefineableTriangleMesh::adapt()",
30544  OOMPH_EXCEPTION_LOCATION);
30545  } // if (bin_number<0)
30546  else
30547  {
30548  // Go for smallest target area of any element in this bin
30549  // to force "one level" of refinement (the one-level-ness
30550  // is enforced below by limiting the actual reduction in
30551  // area
30552  if (new_transferred_target_area[e]!=0)
30553  {
30554  new_transferred_target_area[e]=
30555  std::min(new_transferred_target_area[e],
30556  bin_min_target_area[bin_number]);
30557  }
30558  else
30559  {
30560  new_transferred_target_area[e]=bin_min_target_area[bin_number];
30561  }
30562 
30563  }
30564 
30565 #endif
30566 
30567  } // for (ipt<nint)
30568 
30569  } // for (e<nelem)
30570 
30571 
30572  // do some output (keep it alive!)
30573  const bool output_target_areas=false;
30574  if (output_target_areas)
30575  {
30576  unsigned length=new_transferred_target_area.size();
30577  for (unsigned u = 0; u < length;u++)
30578  {
30579  oomph_info << "Element" << u << ",target area: "
30580  << new_transferred_target_area[u] << std::endl;
30581  }
30582  }
30583  oomph_info << "Time for loop over integration points in new mesh: "
30584  << TimingHelpers::timer()-t0_loop_int_pts
30585  << std::endl;
30586 
30587 
30588  // {
30589  // tmp.open((Global_string_for_annotation:: String[0]+"binned_target_areas"+
30590  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
30591 
30592  // Vector<Vector<std::pair<FiniteElement*,Vector<double> > > > bin_content=
30593  // mesh_geom_obj_pt->bin_content();
30594  // unsigned nbin=bin_content.size();
30595  // for (unsigned b=0;b<nbin;b++)
30596  // {
30597  // unsigned nentry=bin_content[b].size();
30598  // for (unsigned entry=0;entry<nentry;entry++)
30599  // {
30600  // FiniteElement* el_pt=bin_content[b][entry].first;
30601  // GeneralisedElement* gen_el_pt=bin_content[b][entry].first;
30602  // Vector<double> s=bin_content[b][entry].second;
30603  // Vector<double> x(2);
30604  // el_pt->interpolated_x(s,x);
30605  // unsigned e_current=element_number[gen_el_pt];
30606  // tmp << x[0] << " " << x[1] << " "
30607  // << target_area[e_current] << " "
30608  // << el_pt->size() << " "
30609  // << std::endl;
30610  // }
30611  // }
30612  // tmp.close();
30613  // }
30614 
30615  const double t_sub_total_transfer_target_areas =
30616  TimingHelpers::timer()-t_start_transfer_target_areas;
30617 
30618  if (Print_timings_level_adaptation>2)
30619  {
30620  // Get the number of elements in the old mesh (this)
30621  const unsigned n_element = this->nelement();
30622  // Get the number of elements in the background mesh
30623  const unsigned n_element_background = tmp_new_mesh_pt->nelement();
30624 
30625  oomph_info << "CPU for transfer of target areas "
30626  << "[n_ele_old_mesh="
30627  << n_element <<", n_ele_background_mesh="
30628  << n_element_background<<"] (iter "<< iter << "): "
30629  << t_sub_total_transfer_target_areas<< std::endl;
30630  }
30631 
30632  // Add the timing for tranfer of target areas
30633  t_total_transfer_target_areas+=t_sub_total_transfer_target_areas;
30634 
30635  // // Output mesh
30636  // tmp_new_mesh_pt->output(("intermediate_mesh"+
30637  // StringConversion::to_string(iter)+".dat").c_str());
30638 
30639  // tmp.open((Global_string_for_annotation:: String[0]+"target_areas_intermediate_mesh_iter"+
30640  // StringConversion::to_string(iter)+"_"+
30641  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
30642 
30643  const double t_start_limit_target_areas = TimingHelpers::timer();
30644 
30645  // Now copy into target area for temporary mesh but limit to
30646  // the equivalent of one sub-division per iteration
30647 #ifdef OOMPH_HAS_MPI
30648  unsigned n_ele_need_refinement_iter = 0;
30649 #endif
30650 
30651 
30652  // Don't delete! Keep these around for debugging
30653  // ofstream tmp_mesh_file;
30654  // tmp_mesh_file.open("tmp_mesh_file.dat");
30655  // tmp_new_mesh_pt->output(tmp_mesh_file);
30656  // tmp_mesh_file.close();
30657  // ofstream target_areas_file;
30658  // target_areas_file.open("target_areas_file.dat");
30659 
30660  const unsigned nel_new=tmp_new_mesh_pt->nelement();
30661  Vector<double> new_target_area(nel_new);
30662  for (unsigned e=0;e<nel_new;e++)
30663  {
30664  // The finite element
30665  FiniteElement* f_ele_pt = tmp_new_mesh_pt->finite_element_pt(e);
30666 
30667  // Transferred target area
30668  const double new_area=new_transferred_target_area[e];
30669  if (new_area<=0.0)
30670  {
30671  std::ostringstream error_stream;
30672  error_stream << "This shouldn't happen! Element whose centroid is at "
30673  << (f_ele_pt->node_pt(0)->x(0)+
30674  f_ele_pt->node_pt(1)->x(0)+
30675  f_ele_pt->node_pt(2)->x(0))/3.0 << " "
30676  << (f_ele_pt->node_pt(0)->x(1)+
30677  f_ele_pt->node_pt(1)->x(1)+
30678  f_ele_pt->node_pt(2)->x(1))/3.0 << " "
30679  << " has no target area assigned\n";
30680  throw OomphLibError(error_stream.str(),
30681  OOMPH_CURRENT_FUNCTION,
30682  OOMPH_EXCEPTION_LOCATION);
30683  }
30684  else
30685  {
30686 
30687 
30688  // Limit target area to the equivalent of uniform refinement
30689  // during this stage of the iteration
30690  new_target_area[e]=new_area;
30691  if (new_target_area[e]<f_ele_pt->size()/3.0)
30692  {
30693  new_target_area[e]=f_ele_pt->size()/3.0;
30694 
30695  // We'll need to give it another go later
30696  done=false;
30697 
30698  }
30699 
30700  // Don't delete! Keep around for debugging
30701  // target_areas_file
30702  // << (f_ele_pt->node_pt(0)->x(0)+
30703  // f_ele_pt->node_pt(1)->x(0)+
30704  // f_ele_pt->node_pt(2)->x(0))/3.0 << " "
30705  // << (f_ele_pt->node_pt(0)->x(1)+
30706  // f_ele_pt->node_pt(1)->x(1)+
30707  // f_ele_pt->node_pt(2)->x(1))/3.0 << " "
30708  // << new_area << " "
30709  // << new_target_area[e] << std::endl;
30710 
30711 
30712 
30713 #ifdef OOMPH_HAS_MPI
30714  // Keep track of the elements that require (un)refinement
30715  n_ele_need_refinement_iter++;
30716 #endif
30717 
30718  } // else if (new_area <= 0.0)
30719 
30720  } // for (e < nel_new)
30721 
30722 
30723  // Don't delete! Keep around for debugging
30724  // target_areas_file.close();
30725 
30726  const double t_sub_total_limit_target_areas =
30727  TimingHelpers::timer() - t_start_limit_target_areas;
30728 
30729  // Add the timing for copying target areas
30730  t_total_limit_target_areas+=t_sub_total_limit_target_areas;
30731 
30732  if (Print_timings_level_adaptation>2)
30733  {
30734  // Get the number of elements in the old mesh (this)
30735  const unsigned n_element = this->nelement();
30736  // Get the number of elements in the background mesh
30737  const unsigned n_element_background = tmp_new_mesh_pt->nelement();
30738 
30739  oomph_info << "CPU for limiting target areas "
30740  << "[n_ele_old_mesh="
30741  << n_element <<", n_ele_background_mesh="
30742  << n_element_background<<"] (iter "<< iter << "): "
30743  << t_sub_total_limit_target_areas<< std::endl;
30744  }
30745 
30746  if (done)
30747  {
30748  oomph_info
30749  << "All area adjustments accommodated by max. permitted area"
30750  << " reduction \n";
30751  }
30752  else
30753  {
30754  oomph_info
30755  << "NOT all area adjustments accommodated by max. "
30756  << "permitted area reduction \n";
30757  }
30758 
30759  //tmp.close();
30760  //pause("doced binned_target_areas.dat and intermediate mesh targets");
30761 
30762  // Now create the new mesh from TriangulateIO structure
30763  //-----------------------------------------------------
30764  // associated with uniform background mesh and the
30765  //------------------------------------------------
30766  // associated target element sizes.
30767  //---------------------------------
30768 
30769  const double t_start_create_new_adapted_mesh =
30771 
30772  // Solid mesh?
30773  if (solid_mesh_pt!=0)
30774  {
30775  new_mesh_pt=new RefineableSolidTriangleMesh<ELEMENT>
30776  (new_target_area,
30777  tmp_new_triangulateio,
30778  this->Time_stepper_pt,
30779  this->Use_attributes,
30780  this->Allow_automatic_creation_of_vertices_on_boundaries,
30781  this->communicator_pt());
30782  }
30783  // No solid mesh
30784  else
30785  {
30786  new_mesh_pt=new RefineableTriangleMesh<ELEMENT>
30787  (new_target_area,
30788  tmp_new_triangulateio,
30789  this->Time_stepper_pt,
30790  this->Use_attributes,
30791  this->Allow_automatic_creation_of_vertices_on_boundaries,
30792  this->communicator_pt());
30793  }
30794 
30795  // Sub-total to create new adapted mesh
30796  const double t_sub_total_create_new_adapted_mesh =
30797  TimingHelpers::timer() - t_start_create_new_adapted_mesh;
30798 
30799  // Add the time to the total snap nodes time
30800  t_total_create_new_adapted_mesh+=t_sub_total_create_new_adapted_mesh;
30801 
30802  if (Print_timings_level_adaptation>2)
30803  {
30804  // Get the number of elements of the new adapted mesh
30805  const unsigned n_element_new_adapted_mesh = new_mesh_pt->nelement();
30806 
30807  oomph_info << "CPU for creation of new adapted mesh "
30808  << t_sub_total_create_new_adapted_mesh
30809  << "[nele="<<n_element_new_adapted_mesh
30810  << "] (iter "<< iter << "): "
30811  << t_sub_total_create_new_adapted_mesh << std::endl;
30812  }
30813 
30814 #ifdef OOMPH_HAS_MPI
30815  // ------------------------------------------
30816  // DISTRIBUTED MESH: BEGIN
30817  // ------------------------------------------
30818 
30819  // This section is only required if we are dealing with
30820  // distributed meshes, otherwise there are not shared boundaries
30821  // overlapping internal boundaries
30822 
30823  // Check if necessary to fill boundary elements for those internal
30824  // boundaries that overlap shared boundaries
30825  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30826  {
30827  // Copy the data structures that indicate which shared
30828  // boundaries are part of an internal boundary
30830  this->shared_boundary_overlaps_internal_boundary();
30831 
30832  // Copy the data structure that indicates which are the shared
30833  // boundaries in each processor
30834  new_mesh_pt->shared_boundaries_ids() =
30835  this->shared_boundaries_ids();
30836 
30837  // Fill the structures for the boundary elements and face indexes
30838  // of the boundary elements
30839  new_mesh_pt->
30840  fill_boundary_elements_and_nodes_for_internal_boundaries();
30841  }
30842  // ------------------------------------------
30843  // DISTRIBUTED MESH: END
30844  // ------------------------------------------
30845 #endif // #ifdef OOMPH_HAS_MPI
30846 
30847  // Snap to curvilinear boundaries (some code duplication as this
30848  // is repeated below but helper function would take so many
30849  // arguments that it's nearly as messy...
30850 
30851  //Pass the boundary geometric objects to the new mesh
30852  new_mesh_pt->boundary_geom_object_pt() =
30853  this->boundary_geom_object_pt();
30854 
30855  // Reset the boundary coordinates if there is
30856  // a geometric object associated with the boundary
30857  new_mesh_pt->boundary_coordinate_limits() =
30858  this->boundary_coordinate_limits();
30859 
30860  const double t_start_third_stage_segments_connectivity =
30862 
30863  for (unsigned b=0;b<n_boundary;b++)
30864  {
30865  // ------------------------------------------
30866  // DISTRIBUTED MESH: BEGIN
30867  // ------------------------------------------
30868 
30869  // Before setting up boundary coordinates for the new mesh we
30870  // require to identify the segments with the old mesh to
30871  // assign initial zeta values
30872 #ifdef OOMPH_HAS_MPI
30873  if (this->is_mesh_distributed())
30874  {
30875  // Identify the segments of the new mesh with the ones of
30876  // the original mesh
30877  new_mesh_pt->
30878  identify_boundary_segments_and_assign_initial_zeta_values(b,this);
30879  }
30880 #endif
30881  // ------------------------------------------
30882  // DISTRIBUTED MESH: END
30883  // ------------------------------------------
30884 
30885  // Setup boundary coordinates for boundaries with GeomObject
30886  // associated
30887  if(new_mesh_pt->boundary_geom_object_pt(b)!=0)
30888  {
30889  new_mesh_pt->template setup_boundary_coordinates<ELEMENT>(b);
30890  }
30891 
30892  }
30893 
30894  t_total_third_stage_segments_connectivity+=
30895  TimingHelpers::timer() - t_start_third_stage_segments_connectivity;
30896 
30897  const double t_start_snap_nodes_new_mesh=TimingHelpers::timer();
30898  //Move the nodes on the new boundary onto the old curvilinear
30899  //boundary. If the boundary is straight this will do precisely
30900  //nothing but will be somewhat inefficient
30901  for(unsigned b=0;b<n_boundary;b++)
30902  {
30903  this->snap_nodes_onto_boundary(new_mesh_pt,b);
30904  }
30905 
30906  const double t_sub_total_snap_nodes_new_mesh =
30907  TimingHelpers::timer() - t_start_snap_nodes_new_mesh;
30908 
30909  // Add the time to the total snap nodes time
30910  t_total_snap_nodes+=t_sub_total_snap_nodes_new_mesh;
30911 
30912  if (Print_timings_level_adaptation>2)
30913  {
30914  oomph_info << "CPU for snapping nodes onto boundaries (new mesh) "
30915  << "(iter "<<iter<<"): "
30916  << t_sub_total_snap_nodes_new_mesh<< std::endl;
30917  }
30918 
30919  // Update mesh further?
30920  if (Mesh_update_fct_pt!=0)
30921  {
30922  Mesh_update_fct_pt(new_mesh_pt);
30923  }
30924 
30925  //If we have a continuation problem
30926  //any problem in which the timestepper is a "generalisedtimestepper",
30927  //which will have been set by the problem, then ensure
30928  //all data in the new mesh has the appropriate timestepper
30929  if(dynamic_cast<GeneralisedTimeStepper*>(this->Time_stepper_pt))
30930  {
30932  this->Time_stepper_pt,false);
30933  new_mesh_pt->set_mesh_level_time_stepper(this->Time_stepper_pt,false);
30934  }
30935 
30936  // Not done: get ready for another iteration
30937  iter++;
30938  delete tmp_new_mesh_pt;
30939 
30940 #ifdef OOMPH_HAS_MPI
30941  // Check whether the number of elements that need (un)refinement
30942  // from the previous iteration is the same, if that is the case
30943  // then we mark this processor as done
30944  if (n_ele_need_refinement_iter == n_ele_need_refinement)
30945  {done = true;}
30946  // Update the number of elements that require further
30947  // (un)refinement
30948  n_ele_need_refinement = n_ele_need_refinement_iter;
30949 #endif // #ifdef OOMPH_HAS_MPI
30950 
30951  // ------------------------------------------
30952  // DISTRIBUTED MESH: BEGIN
30953  // ------------------------------------------
30954 
30955  // We can only finish the iteration adaptation process if ALL
30956  // the involved processor are marked as done, otherwise, ALL
30957  // processor need to go for another iteration
30958 #ifdef OOMPH_HAS_MPI
30959  if (this->is_mesh_distributed())
30960  {
30961  // Time to check whether other processors have finish to adapt
30962  const double t_start_wait_other_processors = TimingHelpers::timer();
30963 
30964  // In case that the mesh is distributed it is necessary to
30965  // verify that no processor requires further refinement. If at
30966  // least one processor needs more refinement then all
30967  // processors need to go for another iteration to participate
30968  // in the communications
30969  unsigned this_processor_requires_another_iteration = 1;
30970 
30971  // Is this processor done?
30972  if (done){this_processor_requires_another_iteration = 0;}
30973  int nproc_not_done = this_processor_requires_another_iteration;
30974  // Get the communicator of the mesh
30975  OomphCommunicator* comm_pt = this->communicator_pt();
30976  // Communicate with all procesoors to check whether we need to
30977  // re-iterate
30978  MPI_Allreduce(&this_processor_requires_another_iteration,
30979  &nproc_not_done,1,
30980  MPI_UNSIGNED,MPI_SUM,comm_pt->mpi_comm());
30981  // Are all processors done?
30982  if (nproc_not_done > 0)
30983  {
30984  oomph_info << "At least one processors requires further refinement. "
30985  << "Go for another iteration." << std::endl;
30986  done = false;
30987  }
30988 
30989  // Total to check whether other processors have finish to
30990  // adapt
30991  const double t_sub_total_wait_other_processors =
30992  TimingHelpers::timer() - t_start_wait_other_processors;
30993 
30994  // Add to the total timings to check whether other processors
30995  // need to adapt
30996  t_total_wait_other_processors+=t_sub_total_wait_other_processors;
30997 
30998  if (Print_timings_level_adaptation>2)
30999  {
31000  oomph_info << "CPU for waiting other processors "
31001  << "(iter "<<iter<<"): "
31002  << t_sub_total_wait_other_processors
31003  << std::endl;
31004  }
31005 
31006  } // if (this->is_mesh_distributed())
31007 #endif
31008  // ------------------------------------------
31009  // DISTRIBUTED MESH: END
31010  // ------------------------------------------
31011 
31012  if (!done)
31013  {
31014  oomph_info << "Going for another iteration. Current iteration ("
31015  << iter << ")" << std::endl;
31016 
31017  // Use the new mesh as the tmp mesh
31018  tmp_new_mesh_pt=new_mesh_pt;
31019  tmp_new_triangulateio=new_mesh_pt->triangulateio_representation();
31020  }
31021 
31022  } // end of iteration (while (!done))
31023 
31024  //Delete the temporary geometric object representation of the
31025  //current mesh
31026  delete mesh_geom_obj_pt;
31027 
31028  oomph_info << "CPU for iterative generation of new mesh (TOTAL): "
31029  << TimingHelpers::timer()-t_iter
31030  << std::endl;
31031 
31032  if (Print_timings_level_adaptation>1)
31033  {
31034  oomph_info << "-- CPU for creating new adapted meshes (TOTAL): "
31035  << t_total_create_new_adapted_mesh << std::endl;
31036 
31037  oomph_info << "-- CPU for limiting target areas (TOTAL): "
31038  << t_total_limit_target_areas << std::endl;
31039 
31040  oomph_info << "-- CPU for transferring target areas (TOTAL): "
31041  << t_total_transfer_target_areas << std::endl;
31042 
31043  oomph_info << "-- CPU for waiting other processors (TOTAL): "
31044  << t_total_wait_other_processors << std::endl;
31045  }
31046 
31047  // ==============================================================
31048  // END: Transferring of target areas and creation of new mesh
31049  // ==============================================================
31050 
31051  // ==============================================================
31052  // BEGIN: Project solution from the old to the new mesh
31053  // ==============================================================
31054 
31055  // Check that the projection step is not disabled
31056  if (!Disable_projection)
31057  {
31058  // Take the time for the projection step
31059  double tt_start_projection=TimingHelpers::timer();
31060 
31061  // Print info. for tranfering target areas
31062  if (Print_timings_projection)
31063  {
31064  // Switch timings and stats on
31068  }
31069 
31070  double t_proj=TimingHelpers::timer();
31071  oomph_info << "About to begin projection.\n";
31072 
31073  // Project current solution onto new mesh
31074  //---------------------------------------
31075  ProjectionProblem<ELEMENT>* project_problem_pt=
31077 
31078  // Projection requires to be enabled as distributed if working
31079  // with a distributed mesh
31080 #ifdef OOMPH_HAS_MPI
31081  if (this->is_mesh_distributed())
31082  {
31083  // ------------------------------------------
31084  // DISTRIBUTED MESH: BEGIN
31085  // ------------------------------------------
31086 
31087  // We need to back up the time stepper object since the
31088  // projection class creates a new one
31089  Time* backed_up_time_pt = this->Time_stepper_pt->time_pt();
31090 
31091  // Set the projection problem as distributed
31092  project_problem_pt->enable_problem_distributed();
31093 
31094  // Pass the time stepper to the projection problem (used when
31095  // setting multi_domain_interation)
31096  project_problem_pt->add_time_stepper_pt(this->Time_stepper_pt);
31097 
31098  // Set the mesh used for the projection object
31099  project_problem_pt->mesh_pt()=new_mesh_pt;
31100  //project_problem_pt->disable_suppress_output_during_projection();
31101 
31102  // Use iterative solver for projection? By default, an iterative
31103  // solver is used for the projection stage
31104  if(!this->use_iterative_solver_for_projection())
31105  {
31106  project_problem_pt->disable_use_iterative_solver_for_projection();
31107  }
31108 
31109  // Do the projection
31110  project_problem_pt->project(this);
31111 
31112  // Reset the time stepper object (only affects distributed meshes)
31113  this->Time_stepper_pt->time_pt() = backed_up_time_pt;
31114 
31115  // ------------------------------------------
31116  // DISTRIBUTED MESH: END
31117  // ------------------------------------------
31118 
31119  } // if (this->is_mesh_distributed())
31120  else
31121 #endif // #ifdef OOMPH_HAS_MPI
31122  {
31123  // Set the mesh used for the projection object
31124  project_problem_pt->mesh_pt()=new_mesh_pt;
31125 
31126  // project_problem_pt->disable_suppress_output_during_projection();
31127 
31128  // Use iterative solver for projection? By default, an iterative
31129  // solver is used for the projection stage
31130  if(!this->use_iterative_solver_for_projection())
31131  {
31132  project_problem_pt->disable_use_iterative_solver_for_projection();
31133  }
31134 
31135  // Do the projection
31136  project_problem_pt->project(this);
31137  }
31138 
31139  // Reset printing info. for projection
31140  if (Print_timings_projection)
31141  {
31142  // Switch timings and stats off
31146  }
31147 
31148  // Get the total time for projection
31149  const double tt_projection = TimingHelpers::timer()-tt_start_projection;
31150 
31151  if (Print_timings_level_adaptation>1)
31152  {
31153  // Get the number of elements in the old mesh (this)
31154  const unsigned n_element = this->nelement();
31155  // Get the number of elements in the new mesh
31156  const unsigned n_element_new = new_mesh_pt->nelement();
31157  oomph_info << "CPU for projection (in mesh adaptation) "
31158  << "[n_ele_old_mesh="<< n_element
31159  <<", n_ele_new_mesh="<< n_element_new<<"]: "
31160  << tt_projection << std::endl;
31161 
31162  // ------------------------------------------
31163  // DISTRIBUTED MESH: BEGIN
31164  // ------------------------------------------
31165 #ifdef OOMPH_HAS_MPI
31166  if (this->is_mesh_distributed())
31167  {
31168  // The maximum number of elements in the mesh (over all
31169  // processors)
31170  unsigned n_this_element_new = n_element_new;
31171  unsigned n_max_element_new_global = 0;
31172  // Get the maximum number of elements over all processors
31173  MPI_Reduce(&n_this_element_new, &n_max_element_new_global,
31174  1, MPI_UNSIGNED, MPI_MAX, 0,
31175  this->communicator_pt()->mpi_comm());
31176 
31177  // The time for projection for this processor
31178  double tt_this_projection = tt_projection;
31179  double tt_global_min_projection = 0.0;
31180  double tt_global_max_projection = 0.0;
31181 
31182  // Get the minimum and maximum time for projection
31183  MPI_Reduce(&tt_this_projection, &tt_global_min_projection,
31184  1, MPI_DOUBLE, MPI_MIN, 0,
31185  this->communicator_pt()->mpi_comm());
31186  MPI_Reduce(&tt_this_projection, &tt_global_max_projection,
31187  1, MPI_DOUBLE, MPI_MAX, 0,
31188  this->communicator_pt()->mpi_comm());
31189 
31190  if (this->communicator_pt()->my_rank() == 0)
31191  {
31192  oomph_info << "CPU for projection global (MIN): "
31193  << tt_global_min_projection << std::endl;
31194  oomph_info << "CPU for projection global (MAX) "
31195  << "[n_max_ele_new_global="
31196  << n_max_element_new_global<<"]: "
31197  << tt_global_max_projection << std::endl;
31198 
31199  std::cerr << "CPU for projection global (MIN): "
31200  << tt_global_min_projection << std::endl;
31201  std::cerr << "CPU for projection global (MAX): "
31202  << "[n_max_ele_new_global="
31203  << n_max_element_new_global<<"]: "
31204  << tt_global_max_projection << std::endl;
31205 
31206  }
31207 
31208  }
31209 #endif // #ifdef OOMPH_HAS_MPI
31210  // ------------------------------------------
31211  // DISTRIBUTED MESH: END
31212  // ------------------------------------------
31213 
31214  } // if (Print_timings_level_adaptation>1)
31215 
31216  oomph_info << "CPU for projection of solution onto new mesh: "
31217  << TimingHelpers::timer()-t_proj
31218  << std::endl;
31219 
31220  // Delete the projection problem
31221  delete project_problem_pt;
31222 
31223  } // if (!Disable_projection)
31224  else
31225  {
31226  oomph_info << "Projection disabled! The new mesh will contain zeros"
31227  << std::endl;
31228  }
31229 
31230  // ==============================================================
31231  // END: Project solution from the old to the new mesh
31232  // ==============================================================
31233 
31234  double t_rest=TimingHelpers::timer();
31235 
31236  //Flush the old mesh
31237  unsigned nnod=nnode();
31238  for(unsigned j=nnod;j>0;j--)
31239  {
31240  delete Node_pt[j-1];
31241  Node_pt[j-1] = 0;
31242  }
31243  unsigned nel=nelement();
31244  for(unsigned e=nel;e>0;e--)
31245  {
31246  delete Element_pt[e-1];
31247  Element_pt[e-1] = 0;
31248  }
31249 
31250  // Now copy back to current mesh
31251  //------------------------------
31252  nnod=new_mesh_pt->nnode();
31253  Node_pt.resize(nnod);
31254  nel=new_mesh_pt->nelement();
31255  Element_pt.resize(nel);
31256  for(unsigned j=0;j<nnod;j++)
31257  {
31258  Node_pt[j] = new_mesh_pt->node_pt(j);
31259  }
31260  for(unsigned e=0;e<nel;e++)
31261  {
31262  Element_pt[e] = new_mesh_pt->element_pt(e);
31263  }
31264 
31265  // Copy the boundary elements information from the new mesh to the
31266  // original mesh
31267  unsigned nbound = 0;
31268 
31269 #ifdef OOMPH_HAS_MPI
31270  // If working with a distributed mesh we need to change the number
31271  // of boundaries so that shared boundaries information is also
31272  // copied from the old to the new mesh
31273  if (this->is_mesh_distributed())
31274  {
31275  // The boundaries to be copied include those new ones in the new
31276  // mesh (shared boundaries). This info. is required to
31277  // re-establish the halo/haloed scheme
31278  nbound = new_mesh_pt->nboundary();
31279  // After halo and haloed scheme has been re-established the
31280  // number of boundaries is changed to the original number of
31281  // boundaries
31282  }
31283  else
31284 #endif
31285  {
31286  // The original number of boundaries
31287  nbound = n_boundary;
31288  }
31289 
31290  Boundary_element_pt.resize(nbound);
31291  Face_index_at_boundary.resize(nbound);
31292  Boundary_node_pt.resize(nbound);
31293  for (unsigned b=0;b<nbound;b++)
31294  {
31295  unsigned nel=new_mesh_pt->nboundary_element(b);
31296  Boundary_element_pt[b].resize(nel);
31297  Face_index_at_boundary[b].resize(nel);
31298  for (unsigned e=0;e<nel;e++)
31299  {
31300  Boundary_element_pt[b][e]=new_mesh_pt->boundary_element_pt(b,e);
31301  Face_index_at_boundary[b][e]=new_mesh_pt->face_index_at_boundary(b,e);
31302  }
31303  unsigned nnod=new_mesh_pt->nboundary_node(b);
31304  Boundary_node_pt[b].resize(nnod);
31305  for (unsigned j=0;j<nnod;j++)
31306  {
31307  Boundary_node_pt[b][j]=new_mesh_pt->boundary_node_pt(b,j);
31308  }
31309  }
31310 
31311  //Also copy over the new boundary and region information
31312  unsigned n_region = new_mesh_pt->nregion();
31313  // Only bother if we have regions
31314  if(n_region > 1)
31315  {
31316  //Deal with the region information first
31317  this->Region_attribute.resize(n_region);
31318  for(unsigned r=0;r<n_region;r++)
31319  {
31320  this->Region_attribute[r] = new_mesh_pt->region_attribute(r);
31321  // Get the region id
31322  unsigned r_id = static_cast<unsigned>(this->Region_attribute[r]);
31323  //Find the number of elements in the region
31324  unsigned n_region_element = new_mesh_pt->nregion_element(r_id);
31325  this->Region_element_pt[r_id].resize(n_region_element);
31326  for(unsigned e=0;e<n_region_element;e++)
31327  {
31328  this->Region_element_pt[r_id][e] =
31329  new_mesh_pt->region_element_pt(r_id,e);
31330  }
31331  }
31332 
31333  //Now the boundary region information
31334  this->Boundary_region_element_pt.resize(nbound);
31335  this->Face_index_region_at_boundary.resize(nbound);
31336 
31337  //Now loop over the boundaries
31338  for(unsigned b=0;b<nbound;++b)
31339  {
31340  for (unsigned rr = 0 ; rr < n_region; rr++)
31341  {
31342  // The region id
31343  unsigned r = static_cast<unsigned>(this->Region_attribute[rr]);
31344 
31345  unsigned n_boundary_el_in_region =
31346  new_mesh_pt->nboundary_element_in_region(b,r);
31347 
31348  if(n_boundary_el_in_region > 0)
31349  {
31350  //Allocate storage in the map
31351  this->Boundary_region_element_pt[b][r].
31352  resize(n_boundary_el_in_region);
31353  this->Face_index_region_at_boundary[b][r].
31354  resize(n_boundary_el_in_region);
31355 
31356  //Copy over the information
31357  for(unsigned e=0;e<n_boundary_el_in_region;++e)
31358  {
31359  this->Boundary_region_element_pt[b][r][e]
31360  = new_mesh_pt->boundary_element_in_region_pt(b,r,e);
31361  this->Face_index_region_at_boundary[b][r][e]
31362  = new_mesh_pt->face_index_at_boundary_in_region(b,r,e);
31363  }
31364  }
31365  }
31366  } //End of loop over boundaries
31367 
31368  } //End of case when more than one region
31369 
31370  // ------------------------------------------
31371  // DISTRIBUTED MESH: BEGIN
31372  // ------------------------------------------
31373 
31374  // Re-generate halo(ed) information (only for distributed meshes)
31375 #ifdef OOMPH_HAS_MPI
31376  if (this->is_mesh_distributed())
31377  {
31378  // Delete halo(ed) information in the original mesh, the new
31379  // halo(ed) information is generated usign the info. of the new
31380  // mesh
31381  if (this->is_mesh_distributed())
31382  {
31383  this->Halo_node_pt.clear();
31384  this->Root_halo_element_pt.clear();
31385 
31386  this->Haloed_node_pt.clear();
31387  this->Root_haloed_element_pt.clear();
31388 
31389  this->External_halo_node_pt.clear();
31390  this->External_halo_element_pt.clear();
31391 
31392  this->External_haloed_node_pt.clear();
31393  this->External_haloed_element_pt.clear();
31394  }
31395 
31396  // Re-establish the shared boundary elements and nodes scheme
31397  // before re-establish halo(ed) information
31398  this->reset_shared_boundary_elements_and_nodes();
31399 
31400  // -------------------------------------------------------------
31401  // Remove shared boundary elements and nodes from original
31402  // boundary elements and boundary nodes containers. Shared
31403  // boundary elements and nodes are stored in a special
31404  // container.
31405 
31406  // Get the shared boundaries in this processor with any other
31407  // processor
31408  Vector<unsigned> my_rank_shared_boundaries_ids;
31409  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
31410 
31411  // Get the number of shared boundaries
31412  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
31413  // Loop over the shared boundaries marked as original boundaries
31414  // in tmp_new_mesh
31415  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
31416  {
31417  // Get the boundary id
31418  const unsigned shd_bnd_id = my_rank_shared_boundaries_ids[i];
31419  // Flush any previous relation of shared boundary elements
31420  // marked as original boundary elements in tmp_new_mesh
31421  this->Boundary_element_pt[shd_bnd_id].clear();
31422 
31423  // Get the number of nodes associated with the original
31424  // boundary in tmp_new_mesh that is a shared boundary
31425  const unsigned tmp_nnodes =
31426  this->nshared_boundary_node(shd_bnd_id);
31427  for (unsigned n = 0; n < tmp_nnodes; n++)
31428  {
31429  Node* tmp_node_pt = this->boundary_node_pt(shd_bnd_id, n);
31430  tmp_node_pt->remove_from_boundary(shd_bnd_id);
31431  } // for (n < nnodes)
31432 
31433  } // for (shd_bnd_id < nmy_rank_shd_bnd)
31434 
31435  // Re-set the number of boundaries to the original one
31436  this->set_nboundary(n_boundary);
31437 
31438  // Sort the nodes on the boundaries so that they have the same
31439  // order on all the boundaries
31440  this->sort_nodes_on_shared_boundaries();
31441 
31442  // Re-set the halo(ed) scheme
31443  this->reset_halo_haloed_scheme();
31444 
31445  // Set the correct number of segments for the boundaries with
31446  // geom objects associated
31447  for (unsigned b = 0; b < n_boundary; b++)
31448  {
31449  if (this->boundary_geom_object_pt(b)!=0)
31450  {
31451  const unsigned nsegments = new_mesh_pt->nboundary_segment(b);
31452  this->set_nboundary_segment_node(b, nsegments);
31453  }
31454  }
31455 
31456  // Resume the connections in boundaries were it was suspended
31457  resume_boundary_connections(resume_initial_connection_polyline_pt,
31458  resume_final_connection_polyline_pt);
31459 
31460  } // if (this->is_mesh_distributed())
31461 
31462 #endif // #ifdef OOMPH_HAS_MPI
31463 
31464  // ------------------------------------------
31465  // DISTRIBUTED MESH: END
31466  // ------------------------------------------
31467 
31468  //Snap the newly created nodes onto any geometric objects
31469  this->snap_nodes_onto_geometric_objects();
31470 
31471  // Copy the IDs of the vertex nodes
31472  this->Oomph_vertex_nodes_id=new_mesh_pt->oomph_vertex_nodes_id();
31473 
31474  // Copy TriangulateIO representation
31475  TriangleHelper::clear_triangulateio(this->Triangulateio);
31476  bool quiet=true;
31477  this->Triangulateio=
31479  new_mesh_pt->triangulateio_representation(),quiet);
31480 
31481  // Flush the mesh
31482  new_mesh_pt->flush_element_and_node_storage();
31483 
31484  // Delete the mesh
31485  delete new_mesh_pt;
31486 
31487  // Resume of timings
31488  if (Print_timings_level_adaptation>2)
31489  {
31490  // Report timings related with setting boundary coordinates of
31491  // nodes on segments
31492  oomph_info << "CPU for segments connectivity (first stage) [sec]: "
31493  << t_total_first_stage_segments_connectivity << std::endl;
31494  oomph_info << "CPU for segments connectivity (second stage) [sec]: "
31495  << t_total_second_stage_segments_connectivity << std::endl;
31496  oomph_info << "CPU for segments connectivity (third stage) [sec]: "
31497  << t_total_third_stage_segments_connectivity << std::endl;
31498  }
31499 
31500  if (Print_timings_level_adaptation>1)
31501  {
31502  const double t_total_segments_connectivity =
31503  t_total_first_stage_segments_connectivity +
31504  t_total_second_stage_segments_connectivity +
31505  t_total_third_stage_segments_connectivity;
31506 
31507  oomph_info << "CPU for segments connectivity (TOTAL) [sec]: "
31508  << t_total_segments_connectivity << std::endl;
31509 
31510  if (Print_timings_level_adaptation>2)
31511  {
31512  // Report timings for snapping of nodes onto boundaries
31513  oomph_info << "CPU for snapping nodes onto boundaries "
31514  << "(new mesh): "
31515  << t_total_snap_nodes << std::endl;
31516  }
31517 
31518  t_total_snap_nodes+=t_total_snap_nodes_bg_mesh;
31519  oomph_info << "CPU for snapping nodes onto boundaries (TOTAL): "
31520  << t_total_snap_nodes << std::endl;
31521  }
31522 
31523  double max_area=0.0;
31524  double min_area=0.0;
31525 
31526  this->max_and_min_element_size(max_area, min_area);
31527  oomph_info << "Max/min element size in adapted mesh: "
31528  << max_area << " "
31529  << min_area << std::endl;
31530 
31531  oomph_info << "CPU time for final bits [sec]: "
31532  << TimingHelpers::timer()-t_rest
31533  << std::endl;
31534  }
31535  else
31536  {
31537  oomph_info << "Not enough benefit in adaptation.\n";
31538  Nrefined=0;
31539  Nunrefined=0;
31540  }
31541 
31542  double CPU_for_adaptation = TimingHelpers::timer()-t_start_overall;
31543  oomph_info <<"CPU time for adaptation [sec]: "
31544  << CPU_for_adaptation << std::endl;
31545 
31546  // ------------------------------------------
31547  // DISTRIBUTED MESH: BEGIN
31548  // ------------------------------------------
31549 #ifdef OOMPH_HAS_MPI
31550  if (this->is_mesh_distributed())
31551  {
31552  // Get the communicator
31553  OomphCommunicator* comm_pt = this->communicator_pt();
31554  // Get the total number of processors to compute the average
31555  const unsigned n_proc = comm_pt->nproc();
31556  if (Print_timings_level_adaptation>1 && n_proc>1)
31557  {
31558  double global_min_CPU_for_adaptation = 0.0;
31559  double global_max_CPU_for_adaptation = 0.0;
31560  double global_average_CPU_for_adaptation = 0.0;
31561 
31562  // Get the maximum and minimum of the adaptation times
31563  MPI_Reduce(&CPU_for_adaptation, &global_min_CPU_for_adaptation,
31564  1, MPI_DOUBLE, MPI_MIN, 0, comm_pt->mpi_comm());
31565  MPI_Reduce(&CPU_for_adaptation, &global_max_CPU_for_adaptation,
31566  1, MPI_DOUBLE, MPI_MAX, 0, comm_pt->mpi_comm());
31567  MPI_Reduce(&CPU_for_adaptation, &global_average_CPU_for_adaptation,
31568  1, MPI_DOUBLE, MPI_SUM, 0, comm_pt->mpi_comm());
31569 
31570  // Get the rank of the processor
31571  const unsigned my_rank = comm_pt->my_rank();
31572  if (my_rank==0)
31573  {
31574  oomph_info << "CPU for adaptation (MIN): "
31575  << global_min_CPU_for_adaptation << std::endl;
31576  oomph_info << "CPU for adaptation (MAX): "
31577  << global_max_CPU_for_adaptation << std::endl;
31578  oomph_info << "CPU for adaptation (AVERAGE): "
31579  << global_average_CPU_for_adaptation/n_proc << std::endl;
31580  } // if (my_rank==0)
31581 
31582  } // if (Print_timings_level_adaptation>1&&n_proc>1)
31583 
31584  } // if (this->is_mesh_distributed())
31585 
31586  // ------------------------------------------
31587  // DISTRIBUTED MESH: END
31588  // ------------------------------------------
31589 
31590 #endif // #ifdef OOMPH_HAS_MPI
31591 
31592 
31593 
31594  }
31595 
31596 //=========================================================================
31597  /// \ short Mark the vertices that are not allowed for deletion by
31598  /// the unrefienment/refinement polyline methods. In charge of
31599  /// filling the Boundary_connections_pt structure
31600  //=========================================================================
31601  template<class ELEMENT>
31603  {
31604  // Clear any previous information
31605  //Boundary_chunk_connections_pt.clear();
31606  Boundary_connections_pt.clear();
31607 
31608  // Loop over the boundaries in the domain (outer, internal -- closed
31609  // and open ---, and shared) and get the boundaries ids with
31610  // connections (have or receive)
31611 
31612  // Store the boundaries ids that have or receive connection
31613  std::set<unsigned> boundary_id_with_connections;
31614 
31615  // ------------------------------------------------------------------
31616  // Outer boundaries
31617  // ------------------------------------------------------------------
31618 
31619  // Get the number of outer boundaries (closed boundaries)
31620  const unsigned n_outer_boundaries = this->Outer_boundary_pt.size();
31621 
31622  // Loop over the outer boundaries
31623  for (unsigned i = 0; i < n_outer_boundaries; i++)
31624  {
31625  // Get a temporary polygon representation
31626  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
31627  // Get the number of polylines associated to the current outer
31628  // boundary
31629  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31630  // Loop over the polylines
31631  for (unsigned p = 0; p < n_polyline; p++)
31632  {
31633  // Get a temporary representation of the polyline
31634  TriangleMeshPolyLine* tmp_polyline_pt =
31635  tmp_polygon_pt->polyline_pt(p);
31636 
31637  // Is the initial vertex connected?
31638  if (tmp_polyline_pt->is_initial_vertex_connected())
31639  {
31640  // Get the boundary id of the current polyline
31641  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31642 
31643  // Include the boundary id to the set of boundaries with
31644  // connections
31645  boundary_id_with_connections.insert(bnd_id);
31646 
31647  // Boundary id to which the curve is connecte
31648  const unsigned dst_bnd_id =
31649  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31650 
31651  // Include the destination boundary id to the set of
31652  // boundaries with connections
31653  boundary_id_with_connections.insert(dst_bnd_id);
31654 
31655  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31656 
31657  // Is the final vertex connected?
31658  if (tmp_polyline_pt->is_final_vertex_connected())
31659  {
31660  // Get the boundary id of the current polyline
31661  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31662 
31663  // Include the boundary id to the set of boundaries with
31664  // connections
31665  boundary_id_with_connections.insert(bnd_id);
31666 
31667  // Boundary id to which the curve is connected
31668  const unsigned dst_bnd_id =
31669  tmp_polyline_pt->final_vertex_connected_bnd_id();
31670 
31671  // Include the destination boundary id to the set of
31672  // boundaries with connections
31673  boundary_id_with_connections.insert(dst_bnd_id);
31674 
31675  } // if (tmp_polyline_pt->is_final_vertex_connected())
31676 
31677  } // for (p < n_polyline)
31678 
31679  } // for (i < n_outer_boundaries)
31680 
31681  // ------------------------------------------------------------------
31682  // Internal boundaries
31683  // ------------------------------------------------------------------
31684 
31685  // Get the number of internal boundaries (closed boundaries)
31686  const unsigned n_internal_boundaries = this->Internal_polygon_pt.size();
31687 
31688  // Loop over the internal boundaries
31689  for (unsigned i = 0; i < n_internal_boundaries; i++)
31690  {
31691  // Get a temporary polygon representation
31692  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
31693  // Get the number of polylines associated to the current internal
31694  // boundary
31695  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31696  // Loop over the polylines
31697  for (unsigned p = 0; p < n_polyline; p++)
31698  {
31699  // Get a temporary representation of the polyline
31700  TriangleMeshPolyLine* tmp_polyline_pt =
31701  tmp_polygon_pt->polyline_pt(p);
31702 
31703  // Is the initial vertex connected?
31704  if (tmp_polyline_pt->is_initial_vertex_connected())
31705  {
31706  // Get the boundary id of the current polyline
31707  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31708 
31709  // Include the boundary id to the set of boundaries with
31710  // connections
31711  boundary_id_with_connections.insert(bnd_id);
31712 
31713  // Boundary id to which the curve is connecte
31714  const unsigned dst_bnd_id =
31715  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31716 
31717  // Include the destination boundary id to the set of
31718  // boundaries with connections
31719  boundary_id_with_connections.insert(dst_bnd_id);
31720 
31721  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31722 
31723  // Is the final vertex connected?
31724  if (tmp_polyline_pt->is_final_vertex_connected())
31725  {
31726  // Get the boundary id of the current polyline
31727  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31728 
31729  // Include the boundary id to the set of boundaries with
31730  // connections
31731  boundary_id_with_connections.insert(bnd_id);
31732 
31733  // Boundary id to which the curve is connected
31734  const unsigned dst_bnd_id =
31735  tmp_polyline_pt->final_vertex_connected_bnd_id();
31736 
31737  // Include the destination boundary id to the set of
31738  // boundaries with connections
31739  boundary_id_with_connections.insert(dst_bnd_id);
31740 
31741  } // if (tmp_polyline_pt->is_final_vertex_connected())
31742 
31743  } // for (p < n_polyline)
31744 
31745  } // for (i < n_internal_boundaries)
31746 
31747  // ------------------------------------------------------------------
31748  // Open boundaries (nonclosed internal boundaries)
31749  // ------------------------------------------------------------------
31750 
31751  // Get the number of internal boundaries (open boundaries)
31752  const unsigned n_open_boundaries = this->Internal_open_curve_pt.size();
31753 
31754  // Loop over the internal open boundaries
31755  for (unsigned i = 0; i < n_open_boundaries; i++)
31756  {
31757  // Get a temporary representation for the open curve
31758  TriangleMeshOpenCurve* tmp_open_curve_pt =
31759  this->Internal_open_curve_pt[i];
31760 
31761  // Get the number of curve sections associated to the current
31762  // internal open boundary
31763  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
31764 
31765  // Loop over the curve section
31766  for (unsigned p = 0; p < n_curve_section; p++)
31767  {
31768  // Get a temporary representation of the curve section
31769  // (polyline)
31770  TriangleMeshPolyLine* tmp_polyline_pt =
31771  tmp_open_curve_pt->polyline_pt(p);
31772 
31773  // Is the initial vertex connected?
31774  if (tmp_polyline_pt->is_initial_vertex_connected())
31775  {
31776  // Get the boundary id of the current polyline
31777  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31778 
31779  // Include the boundary id to the set of boundaries with
31780  // connections
31781  boundary_id_with_connections.insert(bnd_id);
31782 
31783  // Boundary id to which the curve is connecte
31784  const unsigned dst_bnd_id =
31785  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31786 
31787  // Include the destination boundary id to the set of
31788  // boundaries with connections
31789  boundary_id_with_connections.insert(dst_bnd_id);
31790 
31791  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31792 
31793  // Is the final vertex connected?
31794  if (tmp_polyline_pt->is_final_vertex_connected())
31795  {
31796  // Get the boundary id of the current polyline
31797  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31798 
31799  // Include the boundary id to the set of boundaries with
31800  // connections
31801  boundary_id_with_connections.insert(bnd_id);
31802 
31803  // Boundary id to which the curve is connected
31804  const unsigned dst_bnd_id =
31805  tmp_polyline_pt->final_vertex_connected_bnd_id();
31806 
31807  // Include the destination boundary id to the set of
31808  // boundaries with connections
31809  boundary_id_with_connections.insert(dst_bnd_id);
31810 
31811  } // if (tmp_polyline_pt->is_final_vertex_connected())
31812 
31813  } // for (p < n_curve_section)
31814 
31815  } // for (i < n_open_boundaries)
31816 
31817 #ifdef OOMPH_HAS_MPI
31818  // ------------------------------------------------------------------
31819  // Shared boundaries (only for distributed meshes)
31820  // ------------------------------------------------------------------
31821 
31822  // Check if we need to include any information associated with
31823  // shared boundaries
31824  if (this->is_mesh_distributed())
31825  {
31826  // Get the rank of the current processor
31827  const unsigned my_rank = this->communicator_pt()->my_rank();
31828 
31829  // Get the number of shared curves in the current processor
31830  const unsigned n_shared_curves =
31831  this->nshared_boundary_curves(my_rank);
31832 
31833  // Loop over the shared curves
31834  for (unsigned i = 0; i < n_shared_curves; i ++)
31835  {
31836  // Get the number of polylines associated to the current shared
31837  // curve
31838  const unsigned n_polyline =
31839  this->nshared_boundary_polyline(my_rank, i);
31840 
31841  // Loop over the polylines associated to the current shared
31842  // curve
31843  for (unsigned p = 0; p < n_polyline; p++)
31844  {
31845  // Get a temporary representation of the shared polyline
31846  TriangleMeshPolyLine* tmp_polyline_pt =
31847  this->shared_boundary_polyline_pt(my_rank, i, p);
31848 
31849  // Is the initial vertex connected?
31850  if (tmp_polyline_pt->is_initial_vertex_connected())
31851  {
31852  // Get the boundary id of the current polyline
31853  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31854 
31855  // Include the boundary id to the set of boundaries with
31856  // connections
31857  boundary_id_with_connections.insert(bnd_id);
31858 
31859  // Boundary id to which the curve is connecte
31860  const unsigned dst_bnd_id =
31861  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31862 
31863  // Include the destination boundary id to the set of
31864  // boundaries with connections
31865  boundary_id_with_connections.insert(dst_bnd_id);
31866 
31867  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31868 
31869  // Is the final vertex connected?
31870  if (tmp_polyline_pt->is_final_vertex_connected())
31871  {
31872  // Get the boundary id of the current polyline
31873  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31874 
31875  // Include the boundary id to the set of boundaries with
31876  // connections
31877  boundary_id_with_connections.insert(bnd_id);
31878 
31879  // Boundary id to which the curve is connected
31880  const unsigned dst_bnd_id =
31881  tmp_polyline_pt->final_vertex_connected_bnd_id();
31882 
31883  // Include the destination boundary id to the set of
31884  // boundaries with connections
31885  boundary_id_with_connections.insert(dst_bnd_id);
31886 
31887  } // if (tmp_polyline_pt->is_final_vertex_connected())
31888 
31889  } // for (p < n_polyline)
31890 
31891  } // for (i < n_shared_curves)
31892 
31893  } // if (this->is_mesh_distributed())
31894 
31895 #endif // #ifdef OOMPH_HAS_MPI
31896 
31897  // ---------------------------------------------------------------
31898  // Get the nodes sorted by segments of the boundaries with
31899  // connections
31900 
31901  // Store the sorted nodes by segments of the boundaries with
31902  // connections
31903  std::map<unsigned, Vector<Vector<Node*> > > bnd_sorted_segment_node_pt;
31904 
31905  // Loop over the boundaries with connections
31906  for (std::set<unsigned>::iterator it =
31907  boundary_id_with_connections.begin();
31908  it != boundary_id_with_connections.end(); it++)
31909  {
31910  // Get the boundary id
31911  const unsigned bnd_id = (*it);
31912 #ifdef OOMPH_HAS_MPI
31913  // Working with a distributed mesh
31914  if (this->is_mesh_distributed())
31915  {
31916  // Get the initial shared boundary id
31917  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
31918  // Is an original or shared boundary
31919  if (bnd_id >= init_shd_bnd_id)
31920  {
31921  // Is a shared boundary
31922 
31923  // Temporary storage for the nodes on the shared boundary
31924  Vector<Vector<Node*> > tmp_shared_nodes_pt;
31925 
31926  // Get the nodes associated to the shared boundary
31927  get_shared_boundary_segment_nodes_helper(bnd_id,
31928  tmp_shared_nodes_pt);
31929 
31930  // Store the nodes associated to the shared boundary
31931  bnd_sorted_segment_node_pt[bnd_id] = tmp_shared_nodes_pt;
31932 
31933  } // if (bnd_id >= init_shd_bnd_id)
31934  else
31935  {
31936  // Is an original boundary
31937 
31938  // Temporary storage for the nodes on the original boundary
31939  Vector<Vector<Node*> > tmp_boundary_nodes_pt;
31940 
31941  // Get the nodes associated to the shared boundary
31942  get_boundary_segment_nodes_helper(bnd_id,
31943  tmp_boundary_nodes_pt);
31944 
31945  // Store the nodes associated to the shared boundary
31946  bnd_sorted_segment_node_pt[bnd_id] = tmp_boundary_nodes_pt;
31947 
31948  } // if (bnd_id >= init_shd_bnd_id)
31949 
31950  } // if (this->is_mesh_distributed())
31951  else
31952 #endif // #ifdef OOMPH_HAS_MPI
31953  {
31954  // Is an original boundary
31955 
31956  // Temporary storage for the nodes on the original boundary
31957  Vector<Vector<Node*> > tmp_boundary_nodes_pt;
31958 
31959  // Get the nodes associated to the shared boundary
31960  get_boundary_segment_nodes_helper(bnd_id,
31961  tmp_boundary_nodes_pt);
31962 
31963  // Store the nodes associated to the shared boundary
31964  bnd_sorted_segment_node_pt[bnd_id] = tmp_boundary_nodes_pt;
31965 
31966  } // if (this->is_mesh_distributed())
31967 
31968  } // Loop over boundaries with connections
31969 
31970  // -----------------------------------------------------------------
31971  // Loop again over the boundaries (original and shared) and search
31972  // for the repeated nodes in those boundaries with connections
31973 
31974  // ------------------------------------------------------------------
31975  // Outer boundaries
31976  // ------------------------------------------------------------------
31977  // Loop over the outer boundaries
31978  for (unsigned i = 0; i < n_outer_boundaries; i++)
31979  {
31980  // Get a temporary polygon representation
31981  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
31982  // Get the number of polylines associated to the current outer
31983  // boundary
31984  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31985  // Loop over the polylines
31986  for (unsigned p = 0; p < n_polyline; p++)
31987  {
31988  // Get a temporary representation of the polyline
31989  TriangleMeshPolyLine* tmp_polyline_pt =
31990  tmp_polygon_pt->polyline_pt(p);
31991 
31992  // Is the initial vertex connected?
31993  if (tmp_polyline_pt->is_initial_vertex_connected())
31994  {
31995  // Get the boundary id of the current polyline
31996  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31997 
31998  // Boundary id to which the curve is connected
31999  const unsigned dst_bnd_id =
32000  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32001 
32002  // Boundary chunk to which the curve is connected
32003  const unsigned dst_chunk =
32004  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32005 
32006  // Get the nodes representation of the current boundary
32007  Vector<Vector<Node*> > src_bnd_node_pt =
32008  bnd_sorted_segment_node_pt[bnd_id];
32009 
32010  // Get the nodes representation of the boundary to connect
32011  Vector<Vector<Node*> > dst_bnd_node_pt =
32012  bnd_sorted_segment_node_pt[dst_bnd_id];
32013 
32014  // Add the repeated node to the list of non delete-able
32015  // vertices
32016  add_non_delete_vertices_from_boundary_helper(
32017  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32018 
32019  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32020 
32021  // Is the final vertex connected?
32022  if (tmp_polyline_pt->is_final_vertex_connected())
32023  {
32024  // Get the boundary id of the current polyline
32025  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32026 
32027  // Boundary id to which the curve is connected
32028  const unsigned dst_bnd_id =
32029  tmp_polyline_pt->final_vertex_connected_bnd_id();
32030 
32031  // Boundary chunk to which the curve is connected
32032  const unsigned dst_chunk =
32033  tmp_polyline_pt->final_vertex_connected_n_chunk();
32034 
32035  // Get the nodes representation of the current boundary
32036  Vector<Vector<Node*> > src_bnd_node_pt =
32037  bnd_sorted_segment_node_pt[bnd_id];
32038 
32039  // Get the nodes representation of the boundary to connect
32040  Vector<Vector<Node*> > dst_bnd_node_pt =
32041  bnd_sorted_segment_node_pt[dst_bnd_id];
32042 
32043  // Add the repeated node to the list of non delete-able
32044  // vertices
32045  add_non_delete_vertices_from_boundary_helper(
32046  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32047 
32048  } // if (tmp_polyline_pt->is_final_vertex_connected())
32049 
32050  } // for (p < n_polyline)
32051 
32052  } // for (i < n_outer_boundaries)
32053 
32054  // ------------------------------------------------------------------
32055  // Internal boundaries
32056  // ------------------------------------------------------------------
32057  // Loop over the internal boundaries
32058  for (unsigned i = 0; i < n_internal_boundaries; i++)
32059  {
32060  // Get a temporary polygon representation
32061  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
32062  // Get the number of polylines associated to the current internal
32063  // boundary
32064  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32065  // Loop over the polylines
32066  for (unsigned p = 0; p < n_polyline; p++)
32067  {
32068  // Get a temporary representation of the polyline
32069  TriangleMeshPolyLine* tmp_polyline_pt =
32070  tmp_polygon_pt->polyline_pt(p);
32071 
32072  // Is the initial vertex connected?
32073  if (tmp_polyline_pt->is_initial_vertex_connected())
32074  {
32075  // Get the boundary id of the current polyline
32076  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32077 
32078  // Boundary id to which the curve is connected
32079  const unsigned dst_bnd_id =
32080  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32081 
32082  // Boundary chunk to which the curve is connected
32083  const unsigned dst_chunk =
32084  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32085 
32086  // Get the nodes representation of the current boundary
32087  Vector<Vector<Node*> > src_bnd_node_pt =
32088  bnd_sorted_segment_node_pt[bnd_id];
32089 
32090  // Get the nodes representation of the boundary to connect
32091  Vector<Vector<Node*> > dst_bnd_node_pt =
32092  bnd_sorted_segment_node_pt[dst_bnd_id];
32093 
32094  // Add the repeated node to the list of non delete-able
32095  // vertices
32096  add_non_delete_vertices_from_boundary_helper(
32097  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32098 
32099  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32100 
32101  // Is the final vertex connected?
32102  if (tmp_polyline_pt->is_final_vertex_connected())
32103  {
32104  // Get the boundary id of the current polyline
32105  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32106 
32107  // Boundary id to which the curve is connected
32108  const unsigned dst_bnd_id =
32109  tmp_polyline_pt->final_vertex_connected_bnd_id();
32110 
32111  // Boundary chunk to which the curve is connected
32112  const unsigned dst_chunk =
32113  tmp_polyline_pt->final_vertex_connected_n_chunk();
32114 
32115  // Get the nodes representation of the current boundary
32116  Vector<Vector<Node*> > src_bnd_node_pt =
32117  bnd_sorted_segment_node_pt[bnd_id];
32118 
32119  // Get the nodes representation of the boundary to connect
32120  Vector<Vector<Node*> > dst_bnd_node_pt =
32121  bnd_sorted_segment_node_pt[dst_bnd_id];
32122 
32123  // Add the repeated node to the list of non delete-able
32124  // vertices
32125  add_non_delete_vertices_from_boundary_helper(
32126  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32127 
32128  } // if (tmp_polyline_pt->is_final_vertex_connected())
32129 
32130  } // for (p < n_polyline)
32131 
32132  } // for (i < n_internal_boundaries)
32133 
32134  // ------------------------------------------------------------------
32135  // Open boundaries (nonclosed internal boundaries)
32136  // ------------------------------------------------------------------
32137  // Loop over the internal open boundaries
32138  for (unsigned i = 0; i < n_open_boundaries; i++)
32139  {
32140  // Get a temporary representation for the open curve
32141  TriangleMeshOpenCurve* tmp_open_curve_pt =
32142  this->Internal_open_curve_pt[i];
32143 
32144  // Get the number of curve sections associated to the current
32145  // internal open boundary
32146  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32147 
32148  // Loop over the curve section
32149  for (unsigned p = 0; p < n_curve_section; p++)
32150  {
32151  // Get a temporary representation of the curve section
32152  // (polyline)
32153  TriangleMeshPolyLine* tmp_polyline_pt =
32154  tmp_open_curve_pt->polyline_pt(p);
32155 
32156  // Is the initial vertex connected?
32157  if (tmp_polyline_pt->is_initial_vertex_connected())
32158  {
32159  // Get the boundary id of the current polyline
32160  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32161 
32162  // Boundary id to which the curve is connected
32163  const unsigned dst_bnd_id =
32164  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32165 
32166  // Boundary chunk to which the curve is connected
32167  const unsigned dst_chunk =
32168  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32169 
32170  // Get the nodes representation of the current boundary
32171  Vector<Vector<Node*> > src_bnd_node_pt =
32172  bnd_sorted_segment_node_pt[bnd_id];
32173 
32174  // Get the nodes representation of the boundary to connect
32175  Vector<Vector<Node*> > dst_bnd_node_pt =
32176  bnd_sorted_segment_node_pt[dst_bnd_id];
32177 
32178  // Add the repeated node to the list of non delete-able
32179  // vertices
32180  add_non_delete_vertices_from_boundary_helper(
32181  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32182 
32183  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32184 
32185  // Is the final vertex connected?
32186  if (tmp_polyline_pt->is_final_vertex_connected())
32187  {
32188  // Get the boundary id of the current polyline
32189  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32190 
32191  // Boundary id to which the curve is connected
32192  const unsigned dst_bnd_id =
32193  tmp_polyline_pt->final_vertex_connected_bnd_id();
32194 
32195  // Boundary chunk to which the curve is connected
32196  const unsigned dst_chunk =
32197  tmp_polyline_pt->final_vertex_connected_n_chunk();
32198 
32199  // Get the nodes representation of the current boundary
32200  Vector<Vector<Node*> > src_bnd_node_pt =
32201  bnd_sorted_segment_node_pt[bnd_id];
32202 
32203  // Get the nodes representation of the boundary to connect
32204  Vector<Vector<Node*> > dst_bnd_node_pt =
32205  bnd_sorted_segment_node_pt[dst_bnd_id];
32206 
32207  // Add the repeated node to the list of non delete-able
32208  // vertices
32209  add_non_delete_vertices_from_boundary_helper(
32210  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32211 
32212  } // if (tmp_polyline_pt->is_final_vertex_connected())
32213 
32214  } // for (p < n_curve_section)
32215 
32216  } // for (i < n_open_boundaries)
32217 
32218 #ifdef OOMPH_HAS_MPI
32219  // ------------------------------------------------------------------
32220  // Shared boundaries (only for distributed meshes)
32221  // ------------------------------------------------------------------
32222 
32223  // Check if we need to include any information associated with
32224  // shared boundaries
32225  if (this->is_mesh_distributed())
32226  {
32227  // Get the rank of the current processor
32228  const unsigned my_rank = this->communicator_pt()->my_rank();
32229 
32230  // Get the number of shared curves in the current processor
32231  const unsigned n_shared_curves =
32232  this->nshared_boundary_curves(my_rank);
32233 
32234  // Loop over the shared curves
32235  for (unsigned i = 0; i < n_shared_curves; i ++)
32236  {
32237  // Get the number of polylines associated to the current shared
32238  // curve
32239  const unsigned n_polyline =
32240  this->nshared_boundary_polyline(my_rank, i);
32241 
32242  // Loop over the polylines associated to the current shared
32243  // curve
32244  for (unsigned p = 0; p < n_polyline; p++)
32245  {
32246  // Get a temporary representation of the shared polyline
32247  TriangleMeshPolyLine* tmp_polyline_pt =
32248  this->shared_boundary_polyline_pt(my_rank, i, p);
32249 
32250  // Is the initial vertex connected?
32251  if (tmp_polyline_pt->is_initial_vertex_connected())
32252  {
32253  // Get the boundary id of the current polyline
32254  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32255 
32256  // Boundary id to which the curve is connected
32257  const unsigned dst_bnd_id =
32258  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32259 
32260  // Boundary chunk to which the curve is connected
32261  const unsigned dst_chunk =
32262  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32263 
32264  // Get the nodes representation of the current boundary
32265  Vector<Vector<Node*> > src_bnd_node_pt =
32266  bnd_sorted_segment_node_pt[bnd_id];
32267 
32268  // Get the nodes representation of the boundary to connect
32269  Vector<Vector<Node*> > dst_bnd_node_pt =
32270  bnd_sorted_segment_node_pt[dst_bnd_id];
32271 
32272  // Add the repeated node to the list of non delete-able
32273  // vertices
32274  add_non_delete_vertices_from_boundary_helper(
32275  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32276 
32277  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32278 
32279  // Is the final vertex connected?
32280  if (tmp_polyline_pt->is_final_vertex_connected())
32281  {
32282  // Get the boundary id of the current polyline
32283  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32284 
32285  // Boundary id to which the curve is connected
32286  const unsigned dst_bnd_id =
32287  tmp_polyline_pt->final_vertex_connected_bnd_id();
32288 
32289  // Boundary chunk to which the curve is connected
32290  const unsigned dst_chunk =
32291  tmp_polyline_pt->final_vertex_connected_n_chunk();
32292 
32293  // Get the nodes representation of the current boundary
32294  Vector<Vector<Node*> > src_bnd_node_pt =
32295  bnd_sorted_segment_node_pt[bnd_id];
32296 
32297  // Get the nodes representation of the boundary to connect
32298  Vector<Vector<Node*> > dst_bnd_node_pt =
32299  bnd_sorted_segment_node_pt[dst_bnd_id];
32300 
32301  // Add the repeated node to the list of non delete-able
32302  // vertices
32303  add_non_delete_vertices_from_boundary_helper(
32304  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32305 
32306  } // if (tmp_polyline_pt->is_final_vertex_connected())
32307 
32308  } // for (p < n_polyline)
32309 
32310  } // for (i < n_shared_curves)
32311 
32312  } // if (this->is_mesh_distributed())
32313 
32314 #endif // #ifdef OOMPH_HAS_MPI
32315 
32316  }
32317 
32318  //=========================================================================
32319  /// \short Adds the vertices from the sources boundary that are
32320  /// repeated in the destination boundary to the list of non
32321  /// delete-able vertices in the destination boundary
32322  //=========================================================================
32323  template<class ELEMENT>
32326  Vector<Vector<Node*> > src_bound_segment_node_pt,
32327  Vector<Vector<Node*> > dst_bound_segment_node_pt,
32328  const unsigned &dst_bnd_id, const unsigned &dst_bnd_chunk)
32329  {
32330  // Get the number of segments in the source boundary
32331  const unsigned n_seg = src_bound_segment_node_pt.size();
32332  // Loop over the segments in the source boundary
32333  for (unsigned iseg = 0; iseg < n_seg; iseg++)
32334  {
32335  // Get the number of nodes in the current segment
32336  const unsigned nnode = src_bound_segment_node_pt[iseg].size();
32337  // Get the left and right node of the current segment
32338  Node* left_node_pt = src_bound_segment_node_pt[iseg][0];
32339  Node* right_node_pt = src_bound_segment_node_pt[iseg][nnode-1];
32340 
32341  // Get the number of segments in the destination boundary
32342  const unsigned n_dst_seg = dst_bound_segment_node_pt.size();
32343  // Loop over the segments in the destination boundary
32344  for (unsigned jseg = 0; jseg < n_dst_seg; jseg++)
32345  {
32346  // Get the number of nodes on the current destination segment
32347  const unsigned n_dst_node = dst_bound_segment_node_pt[jseg].size();
32348  // Loop over the nodes until the node has been found or we have
32349  // visited all the nodes
32350  for (unsigned jnode = 0; jnode < n_dst_node; jnode++)
32351  {
32352  // Get a pointer to the jnode in the destination segment
32353  // boundary
32354  Node* tmp_node_pt = dst_bound_segment_node_pt[jseg][jnode];
32355  // Is the node the same as the left or right node if
32356  // the source segment boundary
32357  if (tmp_node_pt == left_node_pt)
32358  {
32359  // We have foud the node to connect, get the vertex of the node
32360  Vector<double> vertex(2);
32361  vertex[0] = tmp_node_pt->x(0);
32362  vertex[1] = tmp_node_pt->x(1);
32363 
32364  // Establish the vertex coordinate as untouchable in the
32365  // destination boundary during the adaptation process. It
32366  // means that unrefinement can not take off the vertices
32367  // that receive connections in the destination boundary
32368  Boundary_connections_pt[dst_bnd_id].insert(vertex);
32369  //Boundary_chunk_connections_pt[dst_bnd_id][dst_bnd_chunk].
32370  // insert(vertex);
32371 
32372  // return
32373  return;
32374 
32375  } // if (tmp_node_pt == left_node_pt)
32376  else if (tmp_node_pt == right_node_pt)
32377  {
32378  // We have foud the node to connect, get the vertex of the node
32379  Vector<double> vertex(2);
32380  vertex[0] = tmp_node_pt->x(0);
32381  vertex[1] = tmp_node_pt->x(1);
32382 
32383  // Establish the vertex coordinate as untouchable in the
32384  // destination boundary during the adaptation process. It
32385  // means that unrefinement can not take off the vertices
32386  // that receive connections in the destination boundary
32387  //Boundary_chunk_connections_pt[dst_bnd_id][dst_bnd_chunk].
32388  // insert(vertex);
32389  Boundary_connections_pt[dst_bnd_id].insert(vertex);
32390 
32391  // return
32392  return;
32393 
32394  } // else if (tmp_node_pt == right_node_pt)
32395 
32396  } // for (jnode < n_dst_node)
32397 
32398  } // for (jseg < n_dst_seg)
32399 
32400  } // for (iseg < n_seg)
32401 
32402  }
32403 
32404 #ifdef OOMPH_HAS_MPI
32405  //=========================================================================
32406  /// \short Synchronise the vertices that are marked for non deletion
32407  // on the shared boundaries. Unrefinement of shared boundaries is
32408  // performed only if the candidate node is not marked for non deletion
32409  //=========================================================================
32410  template<class ELEMENT>
32413  {
32414  // Get the number of processors
32415  const unsigned nproc = this->communicator_pt()->nproc();
32416  // Get my rank
32417  const unsigned my_rank = this->communicator_pt()->my_rank();
32418 
32419  // loop over the processors
32420  for (unsigned jproc = 0; jproc < nproc; jproc++)
32421  {
32422  // The number of boundaries shared with the current processor
32423  // (if jproc==my_rank then there are no shared boundaries
32424  // between them)
32425  const unsigned n_shd_bnd_jproc =
32426  this->nshared_boundaries(my_rank, jproc);
32427 
32428  // Are there shared boundaries with the jproc processor?
32429  // There are no info. with myself
32430  if (jproc != my_rank && n_shd_bnd_jproc > 0)
32431  {
32432  // Storage for the boundaries ids with vertices for non
32433  // deletion
32434  Vector<unsigned> shd_bnd_id_for_non_deletion;
32435 
32436  // Storage for chunk numbers of boundaries with vertices
32437  // for non deletion
32438  Vector<unsigned> chunk_for_non_deletion;
32439 
32440  // The number of vertices for nondeletion in the shared
32441  // boundaries
32442  Vector<unsigned> number_vertices_non_deletion;
32443 
32444  // Vertices marked for nondeletion in shared boundaries
32445  Vector<Vector<Vector<double> > > vertices_for_non_deletion;
32446 
32447  // Get the boundary ids of the shared boundaries with jproc
32448  // processor
32449  Vector<unsigned> shd_bnd_ids =
32450  this->shared_boundaries_ids(my_rank, jproc);
32451 
32452  // Get the number of shared boundaries with jproc
32453  const unsigned n_shd_bnd_jproc = shd_bnd_ids.size();
32454  // loop over the shared boundaries with jproc
32455  for (unsigned ishd_bnd=0;ishd_bnd<n_shd_bnd_jproc;ishd_bnd++)
32456  {
32457  // Get the shared boudary id
32458  const unsigned shd_bnd_id = shd_bnd_ids[ishd_bnd];
32459  // Get the associated polyline
32460  TriangleMeshPolyLine *shd_polyline_pt =
32461  this->boundary_polyline_pt(shd_bnd_id);
32462  // Get the chunk number
32463  const unsigned chunk = shd_polyline_pt->boundary_chunk();
32464 
32465  // Store the vertices not allowed for deletion
32466  std::set<Vector<double> > no_delete_vertex;
32467 
32468  // Does the boundary has vertives for nondeleteion?
32469  const bool boundary_receive_connections =
32470  this->boundary_connections(shd_bnd_id, chunk,
32471  no_delete_vertex);
32472 
32473  // Get the number of vertices for nondeletion
32474  const unsigned n_non_delete_vertex = no_delete_vertex.size();
32475 
32476  // Are there vertices for nondeletion?
32477  if (boundary_receive_connections && n_non_delete_vertex > 0)
32478  {
32479  // Add the shared boundary id
32480  shd_bnd_id_for_non_deletion.push_back(shd_bnd_id);
32481  // Add the chunk number
32482  chunk_for_non_deletion.push_back(chunk);
32483  // Add the number of vertices for non deletion
32484  number_vertices_non_deletion.push_back(n_non_delete_vertex);
32485 
32486  // The list of vertices to add
32487  Vector<Vector<double> > tmp_vertices;
32488 
32489  // Add the vertices for non deletion
32490  for (std::set<Vector<double> >::iterator it =
32491  no_delete_vertex.begin();
32492  it != no_delete_vertex.end(); it++)
32493  {
32494  // Get the vertex coordinate
32495  Vector<double> vertex = (*it);
32496  tmp_vertices.push_back(vertex);
32497  }
32498 
32499  // Add the vertices coordinates to a vector storage
32500  vertices_for_non_deletion.push_back(tmp_vertices);
32501 
32502  } // if (boundary_receive_connections && n_non_delete_vertex > 0)
32503 
32504  } // for (ishd_bnd<n_shd_bnd_jproc)
32505 
32506  // ----------------------------------------------------------
32507  // ----------------------------------------------------------
32508  // ----------------------------------------------------------
32509  // Now send the info. to the other processor (jproc)
32510  // ----------------------------------------------------------
32511  // ----------------------------------------------------------
32512  // ----------------------------------------------------------
32513  // Get the communicator of the mesh
32514  OomphCommunicator* comm_pt = this->communicator_pt();
32515 
32516  // Set MPI info
32517  MPI_Status status;
32518  MPI_Request request;
32519 
32520  // -----------------------------------------------------------
32521  // Prepare the data
32522  // Get the number of shared boundaires with vertices marked
32523  // for non deletion
32524  const unsigned n_shd_bnd_with_non_delete_vertices =
32525  shd_bnd_id_for_non_deletion.size();
32526 
32527  // Size of the package
32528  const unsigned size_package = 3;
32529  // Ndata to send
32530  const unsigned n_unsigned_data_to_send =
32531  n_shd_bnd_with_non_delete_vertices*size_package;
32532  // The flat package to send the info.
32533  Vector<unsigned> flat_package_unsigned_send(n_unsigned_data_to_send);
32534  Vector<double> flat_package_double_send;
32535 
32536  Vector<unsigned> flat_package_unsigned_recv;
32537  Vector<double> flat_package_double_recv;
32538 
32539  // Prepare the data to be sent
32540  unsigned j=0;
32541  for (unsigned i=0;i<n_shd_bnd_with_non_delete_vertices;i++)
32542  {
32543  // The shared boundary id
32544  flat_package_unsigned_send[j++] =
32545  shd_bnd_id_for_non_deletion[i];
32546  // The chunk number
32547  flat_package_unsigned_send[j++] =
32548  chunk_for_non_deletion[i];
32549  // The number of vertices for nondeletion
32550  flat_package_unsigned_send[j++] =
32551  number_vertices_non_deletion[i];
32552  // Also package the vertices
32553  const unsigned n_vertices_non_deletion =
32554  number_vertices_non_deletion[i];
32555  // Loop over the vertices and store them in the flat
32556  // package to be sent
32557  for (unsigned h=0;h<n_vertices_non_deletion;h++)
32558  {
32559  flat_package_double_send.push_back(
32560  vertices_for_non_deletion[i][h][0]);
32561  flat_package_double_send.push_back(
32562  vertices_for_non_deletion[i][h][1]);
32563  } // for (h<n_vertices_non_deletion)
32564 
32565  } // for (i<n_shd_bnd_with_non_delete_vertices)
32566 
32567  // ----------------------------------------------------------
32568  int send_proc = jproc;
32569  int recv_proc = jproc;
32570  unsigned send_count_unsigned_values = n_unsigned_data_to_send;
32571  unsigned send_count_double_values = flat_package_double_send.size();
32572  //-----------------------------------------------------------
32573  // Do the transfering of info.
32574  //-----------------------------------------------------------
32575  // Start with UNSIGNED info.
32576  MPI_Isend(&send_count_unsigned_values,1,MPI_UNSIGNED,
32577  send_proc,1,comm_pt->mpi_comm(),&request);
32578 
32579  unsigned receive_count_unsigned_values=0;
32580  MPI_Recv(&receive_count_unsigned_values,1,MPI_UNSIGNED,
32581  recv_proc,1,comm_pt->mpi_comm(),&status);
32582 
32583  MPI_Wait(&request,MPI_STATUS_IGNORE);
32584 
32585  // Send the actual data
32586  if (send_count_unsigned_values!=0)
32587  {
32588  MPI_Isend(&flat_package_unsigned_send[0],
32589  send_count_unsigned_values,MPI_UNSIGNED,
32590  send_proc,2,comm_pt->mpi_comm(),&request);
32591  }
32592 
32593  // Receive the actual data
32594  if (receive_count_unsigned_values!=0)
32595  {
32596  flat_package_unsigned_recv.resize(receive_count_unsigned_values);
32597  MPI_Recv(&flat_package_unsigned_recv[0],
32598  receive_count_unsigned_values,
32599  MPI_UNSIGNED,recv_proc,2,comm_pt->mpi_comm(),&status);
32600  }
32601 
32602  // Wait for sending the data and the other processor
32603  // receives
32604  if (send_count_unsigned_values!=0)
32605  {
32606  MPI_Wait(&request,MPI_STATUS_IGNORE);
32607  }
32608 
32609  //-----------------------------------------------------------
32610  // Then continue with DOUBLE info.
32611  MPI_Isend(&send_count_double_values,1,MPI_UNSIGNED,
32612  send_proc,1,comm_pt->mpi_comm(),&request);
32613 
32614  unsigned receive_count_double_values=0;
32615  MPI_Recv(&receive_count_double_values,1,MPI_UNSIGNED,
32616  recv_proc,1,comm_pt->mpi_comm(),&status);
32617 
32618  MPI_Wait(&request,MPI_STATUS_IGNORE);
32619 
32620  // Send the actual data
32621  if (send_count_double_values!=0)
32622  {
32623  MPI_Isend(&flat_package_double_send[0],
32624  send_count_double_values,MPI_DOUBLE,
32625  send_proc,2,comm_pt->mpi_comm(),&request);
32626  }
32627 
32628  // Receive the actual data
32629  if (receive_count_double_values!=0)
32630  {
32631  flat_package_double_recv.resize(receive_count_double_values);
32632  MPI_Recv(&flat_package_double_recv[0],
32633  receive_count_double_values,
32634  MPI_DOUBLE,recv_proc,2,comm_pt->mpi_comm(),&status);
32635  }
32636 
32637  // Wait for sending the data and the other processor
32638  // receives
32639  if (send_count_double_values!=0)
32640  {
32641  MPI_Wait(&request,MPI_STATUS_IGNORE);
32642  }
32643 
32644  // ------------------------------------------------------------
32645  // ------------------------------------------------------------
32646  // ------------------------------------------------------------
32647  // Now unpackage the data
32648  // ------------------------------------------------------------
32649  // ------------------------------------------------------------
32650  // ------------------------------------------------------------
32651 
32652  // Storage for the boundaries ids with vertices for non
32653  // deletion
32654  Vector<unsigned> recv_shd_bnd_id_for_non_deletion;
32655 
32656  // Storage for chunk numbers of boundaries with vertices
32657  // for non deletion
32658  Vector<unsigned> recv_chunk_for_non_deletion;
32659 
32660  // The number of vertices for nondeletion in the shared
32661  // boundaries
32662  Vector<unsigned> recv_number_vertices_non_deletion;
32663 
32664  // Vertices marked for nondeletion in shared boundaries
32665  Vector<Vector<Vector<double> > > recv_vertices_for_non_deletion;
32666 
32667  // Counter
32668  j = 0;
32669  for (unsigned i=0;i<receive_count_unsigned_values;i+=3)
32670  {
32671  // Get the shared boundary id
32672  const unsigned recv_shd_bnd_id =
32673  flat_package_unsigned_recv[i];
32674  recv_shd_bnd_id_for_non_deletion.push_back(recv_shd_bnd_id);
32675  // Get the chunk number
32676  const unsigned recv_chunk =
32677  flat_package_unsigned_recv[i+1];
32678  recv_chunk_for_non_deletion.push_back(recv_chunk);
32679  // Get the number of vertices for non deletion
32680  const unsigned recv_num_vertices =
32681  flat_package_unsigned_recv[i+2];
32682  recv_number_vertices_non_deletion.push_back(recv_num_vertices);
32683 
32684  // Create a temporal storage
32685  Vector<Vector<double> > temp_recv_vertices;
32686  // Now get the vertices
32687  for (unsigned h=0;h<recv_num_vertices;h++)
32688  {
32689  Vector<double> tmp_vertex(2);
32690  tmp_vertex[0] = flat_package_double_recv[j++];
32691  tmp_vertex[1] = flat_package_double_recv[j++];
32692  // Add the vertex to the vector of vertices
32693  temp_recv_vertices.push_back(tmp_vertex);
32694  } // for (h<recv_num_vertices)
32695 
32696  // Add the vertices to the vector of vertices
32697  recv_vertices_for_non_deletion.push_back(temp_recv_vertices);
32698 
32699  } // for(i<receive_count_unsigned_values)
32700 
32701  // ---------------------------------------------------------
32702  // ---------------------------------------------------------
32703  // ---------------------------------------------------------
32704  // Now add the vertices to the data structures to mark them
32705  // as non delete-able
32706  // ---------------------------------------------------------
32707  // ---------------------------------------------------------
32708  // ---------------------------------------------------------
32709 
32710  // Get the number of shd boundaries that have vertices
32711  // marked for non deletion
32712  const unsigned n_recv_shd_bnd_id_for_non_deletion =
32713  recv_shd_bnd_id_for_non_deletion.size();
32714  // loop over the shared boundaries and add the data for non
32715  // deletion
32716  for (unsigned i=0;i<n_recv_shd_bnd_id_for_non_deletion;i++)
32717  {
32718  // Get the shared boundary id.
32719  const unsigned shd_bnd_id =
32720  recv_shd_bnd_id_for_non_deletion[i];
32721  // Get the chunk number
32722  unsigned chunk = recv_chunk_for_non_deletion[i];
32723  // Increase and decrease the chunk number to avoid the
32724  // warning when compiling without PARANOID
32725  chunk++;
32726  chunk--;
32727 
32728  // Get the number of vertices marked for non deletion
32729  const unsigned n_vertices =
32730  recv_number_vertices_non_deletion[i];
32731  // Add all the vertices
32732  for (unsigned h=0;h<n_vertices;h++)
32733  {
32734  // Get the vertex
32735  Vector<double> vertex(2);
32736  vertex[0] = recv_vertices_for_non_deletion[i][h][0];
32737  vertex[1] = recv_vertices_for_non_deletion[i][h][1];
32738  // Add the vertex to the data structure for non
32739  // deletion
32740  //Boundary_chunk_connections_pt[shd_bnd_id][chunk].
32741  // insert(vertex);
32742  Boundary_connections_pt[shd_bnd_id].insert(vertex);
32743 
32744  } // for (h<n_vertices)
32745 
32746  } // for (i<n_recv_shd_bnd_id_for_non_deletion)
32747 
32748  } // if (jproc != my_rank && n_shd_bnd_jproc > 0)
32749 
32750  } // for (jproc < nproc)
32751 
32752  }
32753 #endif // #ifdef OOMPH_HAS_MPI
32754 
32755  //=========================================================================
32756  /// \short After unrefinement and refinement has taken place compute
32757  /// the new vertices numbers of the temporary representation of the
32758  // boundaries to connect.
32759  //=========================================================================
32760  template<class ELEMENT>
32762  Vector<TriangleMeshPolygon *> &tmp_outer_polygons_pt,
32763  Vector<TriangleMeshOpenCurve *> &tmp_open_curves_pt)
32764  {
32765  // Dummy storages
32766  Vector<TriangleMeshPolyLine*> dummy_resume_initial_connection_polyline_pt;
32767  Vector<TriangleMeshPolyLine*> dummy_resume_final_connection_polyline_pt;
32768 
32769  // Clear the storage
32770  dummy_resume_initial_connection_polyline_pt.clear();
32771  dummy_resume_final_connection_polyline_pt.clear();
32772 
32773  // Get the initial shared boundary id (to check whether the
32774  // polylines represent original or shared boundaries)
32775  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
32776 
32777  // ------------------------------------------------------------------
32778  // This seems unnecesary since the outer polygons does not create
32779  // connections with other boundaries (the original ones)
32780  // ------------------------------------------------------------------
32781  // Unnecessary?
32782  // ------------------------------------------------------------------
32783 
32784  // Loop over the temporary outer polygons create the connection
32785  // information of those boundaries marked to be connected at their
32786  // ends
32787 
32788  // ------------------------------------------------------------------
32789  // Temporary outer polygons
32790  // ------------------------------------------------------------------
32791 
32792  // Get the number of outer boundaries (closed boundaries)
32793  const unsigned n_outer_boundaries = tmp_outer_polygons_pt.size();
32794 
32795  // Loop over the outer boundaries
32796  for (unsigned i = 0; i < n_outer_boundaries; i++)
32797  {
32798  // Get a temporary polygon representation
32799  TriangleMeshPolygon* tmp_polygon_pt = tmp_outer_polygons_pt[i];
32800  // Get the number of polylines associated to the current outer
32801  // boundary
32802  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32803  // Loop over the polylines
32804  for (unsigned p = 0; p < n_polyline; p++)
32805  {
32806  // Get a temporary representation of the polyline
32807  TriangleMeshPolyLine* tmp_polyline_pt =
32808  tmp_polygon_pt->polyline_pt(p);
32809 
32810  // Get the boundary id
32811  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32812 
32813  // Is the boundary to connect a shared boundary
32814  if (bnd_id < init_shd_bnd_id)
32815  {
32816  // Restore the connections of the current polyline
32817  restore_polyline_connections_helper(
32818  tmp_polyline_pt,
32819  dummy_resume_initial_connection_polyline_pt,
32820  dummy_resume_final_connection_polyline_pt);
32821 
32822  } // if (bnd_id < init_shd_bnd_id)
32823 
32824  } // for (p < n_polyline)
32825 
32826  } // for (i < n_outer_boundaries)
32827 
32828  // ------------------------------------------------------------------
32829  // Unnecessary?
32830  // ------------------------------------------------------------------
32831 
32832  // ------------------------------------------------------------------
32833  // Temporary open boundaries (nonclosed internal boundaries)
32834  // ------------------------------------------------------------------
32835 
32836  // Get the number of internal boundaries (open boundaries)
32837  const unsigned n_open_boundaries = tmp_open_curves_pt.size();
32838 
32839  // Loop over the internal open boundaries
32840  for (unsigned i = 0; i < n_open_boundaries; i++)
32841  {
32842  // Get a temporary representation for the open curve
32843  TriangleMeshOpenCurve* tmp_open_curve_pt = tmp_open_curves_pt[i];
32844 
32845  // Get the number of curve sections associated to the current
32846  // internal open boundary
32847  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32848 
32849  // Loop over the curve section
32850  for (unsigned p = 0; p < n_curve_section; p++)
32851  {
32852  // Get a temporary representation of the curve section
32853  // (polyline)
32854  TriangleMeshPolyLine* tmp_polyline_pt =
32855  tmp_open_curve_pt->polyline_pt(p);
32856 
32857  // Get the boundary id
32858  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32859 
32860  // Is the boundary to connect a shared boundary
32861  if (bnd_id < init_shd_bnd_id)
32862  {
32863  // Restore the connections of the current polyline
32864  restore_polyline_connections_helper(
32865  tmp_polyline_pt,
32866  dummy_resume_initial_connection_polyline_pt,
32867  dummy_resume_final_connection_polyline_pt);
32868 
32869  } // if (bnd_id < init_shd_bnd_id)
32870 
32871  } // for (p < n_curve_section)
32872 
32873  } // for (i < n_open_boundaries)
32874 
32875  }
32876 
32877  //=========================================================================
32878  /// \short After unrefinement and refinement has taken place compute
32879  /// the new vertices numbers of the boundaries to connect (in a
32880  /// distributed scheme it may be possible that the destination
32881  /// boundary does no longer exist, therefore the connection is
32882  /// suspended. It is not permanently deleted because if load balance
32883  /// takes place it may be possible that the boundary to connect be
32884  /// part of the new domain representation, so the connection would
32885  /// exist)
32886  //=========================================================================
32887  template<class ELEMENT>
32889  Vector<TriangleMeshPolyLine*> &resume_initial_connection_polyline_pt,
32890  Vector<TriangleMeshPolyLine*> &resume_final_connection_polyline_pt)
32891  {
32892  // Clear the storage
32893  resume_initial_connection_polyline_pt.clear();
32894  resume_final_connection_polyline_pt.clear();
32895 
32896  // Loop over the boundaries in the domain (outer, internal -- closed
32897  // and open) and restore the connection information of those
32898  // boundaries marked to be connected at their ends
32899 
32900  // ------------------------------------------------------------------
32901  // Outer boundaries
32902  // ------------------------------------------------------------------
32903 
32904  // Get the number of outer boundaries (closed boundaries)
32905  const unsigned n_outer_boundaries = this->Outer_boundary_pt.size();
32906 
32907  // Loop over the outer boundaries
32908  for (unsigned i = 0; i < n_outer_boundaries; i++)
32909  {
32910  // Get a temporary polygon representation
32911  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
32912  // Get the number of polylines associated to the current outer
32913  // boundary
32914  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32915  // Loop over the polylines
32916  for (unsigned p = 0; p < n_polyline; p++)
32917  {
32918  // Get a temporary representation of the polyline
32919  TriangleMeshPolyLine* tmp_polyline_pt =
32920  tmp_polygon_pt->polyline_pt(p);
32921 
32922  // Restore the connections of the current polyline
32923  restore_polyline_connections_helper(
32924  tmp_polyline_pt,
32925  resume_initial_connection_polyline_pt,
32926  resume_final_connection_polyline_pt);
32927 
32928  } // for (p < n_polyline)
32929 
32930  } // for (i < n_outer_boundaries)
32931 
32932  // ------------------------------------------------------------------
32933  // Internal boundaries
32934  // ------------------------------------------------------------------
32935 
32936  // Get the number of internal boundaries (closed boundaries)
32937  const unsigned n_internal_boundaries = this->Internal_polygon_pt.size();
32938 
32939  // Loop over the internal boundaries
32940  for (unsigned i = 0; i < n_internal_boundaries; i++)
32941  {
32942  // Get a temporary polygon representation
32943  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
32944  // Get the number of polylines associated to the current internal
32945  // boundary
32946  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32947  // Loop over the polylines
32948  for (unsigned p = 0; p < n_polyline; p++)
32949  {
32950  // Get a temporary representation of the polyline
32951  TriangleMeshPolyLine* tmp_polyline_pt =
32952  tmp_polygon_pt->polyline_pt(p);
32953 
32954  // Restore the connections of the current polyline
32955  restore_polyline_connections_helper(
32956  tmp_polyline_pt,
32957  resume_initial_connection_polyline_pt,
32958  resume_final_connection_polyline_pt);
32959 
32960  } // for (p < n_polyline)
32961 
32962  } // for (i < n_internal_boundaries)
32963 
32964  // ------------------------------------------------------------------
32965  // Open boundaries (nonclosed internal boundaries)
32966  // ------------------------------------------------------------------
32967 
32968  // Get the number of internal boundaries (open boundaries)
32969  const unsigned n_open_boundaries = this->Internal_open_curve_pt.size();
32970 
32971  // Loop over the internal open boundaries
32972  for (unsigned i = 0; i < n_open_boundaries; i++)
32973  {
32974  // Get a temporary representation for the open curve
32975  TriangleMeshOpenCurve* tmp_open_curve_pt =
32976  this->Internal_open_curve_pt[i];
32977 
32978  // Get the number of curve sections associated to the current
32979  // internal open boundary
32980  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32981 
32982  // Loop over the curve section
32983  for (unsigned p = 0; p < n_curve_section; p++)
32984  {
32985  // Get a temporary representation of the curve section
32986  // (polyline)
32987  TriangleMeshPolyLine* tmp_polyline_pt =
32988  tmp_open_curve_pt->polyline_pt(p);
32989 
32990  // Restore the connections of the current polyline
32991  restore_polyline_connections_helper(
32992  tmp_polyline_pt,
32993  resume_initial_connection_polyline_pt,
32994  resume_final_connection_polyline_pt);
32995 
32996  } // for (p < n_curve_section)
32997 
32998  } // for (i < n_open_boundaries)
32999 
33000  }
33001 
33002  //=========================================================================
33003  /// \short Restore the connections of the specific polyline
33004  /// The vertices numbering on the destination boundaries may have
33005  /// change because of (un)refinement in the destination boundaries.
33006  /// Also deals with connection that do not longer exist because the
33007  /// destination boundary does no longer exist because of the distribution
33008  /// process
33009  //=========================================================================
33010  template<class ELEMENT>
33013  TriangleMeshPolyLine* polyline_pt,
33014  Vector<TriangleMeshPolyLine*> &resume_initial_connection_polyline_pt,
33015  Vector<TriangleMeshPolyLine*> &resume_final_connection_polyline_pt)
33016  {
33017  // If the polyline is connected at any of its ends compute the new
33018  // vertex number on the destination boundary
33019 
33020  // ------------------------------------------------------------------
33021  // Is the initial vertex connected?
33022  if (polyline_pt->is_initial_vertex_connected())
33023  {
33024  // The pointer to the boundary to connect
33025  TriangleMeshPolyLine *poly_to_connect_pt = 0;
33026 
33027  // Get the boundary id of the destination/connected boundary
33028  const unsigned dst_bnd_id_initial =
33029  polyline_pt->initial_vertex_connected_bnd_id();
33030 
33031  // Get the initial vertex on the current boundary
33032  Vector<double> src_vertex_coordinates_initial =
33033  polyline_pt->vertex_coordinate(0);
33034 
33035 #ifdef PARANOID
33036  // Is the mesh distributed?
33037 #ifdef OOMPH_HAS_MPI
33038  if (this->is_mesh_distributed())
33039  {
33040  // Get the initial shared boundary id
33041  const unsigned init_shd_bnd_id =
33042  this->initial_shared_boundary_id();
33043  // Is the boundary to connect a shared boundary
33044  if (dst_bnd_id_initial >= init_shd_bnd_id)
33045  {
33046  // Get the current polyline original boundary id
33047  const unsigned bnd_id = polyline_pt->boundary_id();
33048  std::ostringstream error_message;
33049  error_message
33050  << "INITIAL VERTEX CONNECTION\n"
33051  << "The current original boundary is trying to connect to a\n"
33052  << "shared boundary, this is not allowed. In this case the\n"
33053  << "shared boundary should be the one that connects with the\n"
33054  << "original boundary\n"
33055  << "The current original boundary (" << bnd_id << ") is marked\n"
33056  << "to have a connection at the\nINITIAL vertex ("
33057  << src_vertex_coordinates_initial[0] << ","
33058  << src_vertex_coordinates_initial[1] << ")\n"
33059  << "with the shared boundary ("<< dst_bnd_id_initial << ")\n"
33060  << "This is the list of vertices on the shared destination boundary\n";
33061  // Get the pointer to the associated polyline by using the
33062  // boundary id
33063  TriangleMeshPolyLine *dst_polyline =
33064  this->boundary_polyline_pt(dst_bnd_id_initial);
33065  // The number of vertices on the destination boundary
33066  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33067  // Loop over the vertices print them
33068  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33069  {
33070  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33071  error_message
33072  << "Vertex#(i): ("
33073  << current_vertex[0] << ", " << current_vertex[1] << ")\n";
33074  }
33075  throw OomphLibError(
33076  error_message.str(),
33077  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33078  OOMPH_EXCEPTION_LOCATION);
33079  } // if (dst_bnd_id_initial >= init_shd_bnd_id)
33080 
33081  } // if (this->is_mesh_distributed())
33082 #endif // #ifdef OOMPH_HAS_MPI
33083 
33084 #endif // #ifdef PARANOID
33085 
33086  // Flag to indicate if the vertex was found on the destination
33087  // boundary
33088  bool found_vertex_on_dst_boundary_initial = false;
33089 
33090  // Flag that stores the chunk number to connect (only used in
33091  // distributed meshes)
33092  unsigned sub_poly_to_connect = 0;
33093 
33094  // Store the vertex number on the destination boundary
33095  unsigned n_vertex_connection_initial = 0;
33096 
33097  // Flags only used in a distributed mesh
33098  // ----------------------------------------
33099  // Flag to indicate we are trying to connect to an split boundary
33100  bool connecting_to_an_split_boundary = false;
33101 
33102  // Flag to indicate we are trying to connecto to an internal
33103  // boundary that is overlaped by a shared boundary)
33104  bool connecting_to_an_overlaped_boundary = false;
33105 
33106 #ifdef OOMPH_HAS_MPI
33107  if (this->is_mesh_distributed())
33108  {
33109  // We can only connect to an original boundary, check if the
33110  // boundary was splitted during the distribution process to
33111  // consider all the chunks (sub-polylines) of the boundary
33112  if (this->boundary_was_splitted(dst_bnd_id_initial))
33113  {
33114  connecting_to_an_split_boundary = true;
33115  } // if (this->boundary_was_splitted(dst_bnd_id_initial))
33116 
33117  // Check if the destination boundary, or any of its chunks is
33118  // marked to be overlapped by a shared boundary, if that is the
33119  // case we can only connect to the chunks that are not
33120  // overlapped by shared boundaries (the shared boundaries are in
33121  // charge of generating the connections with original boundaries
33122  // and with themselves)
33123  if (connecting_to_an_split_boundary)
33124  {
33125  // Get the number of chucks that represent the destination
33126  // boundary
33127  const unsigned n_sub_poly =
33128  this->nboundary_subpolylines(dst_bnd_id_initial);
33129  // Now loop over the chunks of the destination boundary and if
33130  // any of them is marked to be overlaped by a shared boundary
33131  // then set the flag and break the loop
33132  for (unsigned ii =0; ii < n_sub_poly; ii++)
33133  {
33134  if (this->
33135  boundary_marked_as_shared_boundary(dst_bnd_id_initial, ii))
33136  {
33137  // Mark the boundary as being overlaped by a shared
33138  // boundary
33139  connecting_to_an_overlaped_boundary = true;
33140  // Break, no need to look for more overlapings
33141  break;
33142  } // if (boundary_marked_as_shared_boundary(...))
33143  } // for (ii < n_sub_poly)
33144  } // if (connecting_to_an_split_boundary)
33145  else
33146  {
33147  // If not connecting to an split boundary then check if the
33148  // whole destination boundary is overlaped by an internal
33149  // boundary
33150  if (this->
33151  boundary_marked_as_shared_boundary(dst_bnd_id_initial, 0))
33152  {
33153  // Mark the boundary as being overlaped by a shared boundary
33154  connecting_to_an_overlaped_boundary = true;
33155  } // if (boundary_marked_as_shared_boundary(...))
33156  } // else if (connecting_to_an_split_boundary)
33157 
33158  } // if (this->is_mesh_distributed())
33159 
33160 #endif // #ifdef OOMPH_HAS_MPI
33161 
33162  // If we are connecting neither to an split boundary nor an
33163  // overlaped boundary then get the pointer to the original
33164  // boundary
33165  if (!(connecting_to_an_split_boundary ||
33166  connecting_to_an_overlaped_boundary))
33167  {
33168  // Get the polyline pointer representing the destination
33169  // boundary
33170  poly_to_connect_pt = this->boundary_polyline_pt(dst_bnd_id_initial);
33171  } // else if (NOT split, NOT overlaped)
33172 
33173  // Now look for the vertex number on the destination boundary(ies)
33174  // -- in case that the boundary was split ---
33175 
33176  // Do not check for same orientation, that was previously worked
33177  // by interchanging the connections boundaries (if necessary)
33178 
33179  // If the boundary was not split then ...
33180  if (!connecting_to_an_split_boundary)
33181  {
33182  // ... check if the boundary is marked to be overlaped by
33183  // a shared boundary
33184  if (!connecting_to_an_overlaped_boundary)
33185  {
33186  // If that is not the case then we can safely look for the
33187  // vertex number on the destination boundary
33188  found_vertex_on_dst_boundary_initial =
33189  this->get_connected_vertex_number_on_destination_polyline(
33190  poly_to_connect_pt,
33191  src_vertex_coordinates_initial,
33192  n_vertex_connection_initial);
33193 
33194  } // if (!connecting_to_an_overlaped_boundary)
33195  else
33196  {
33197  // If the whole boundary is marked to be overlaped by a shared
33198  // boundary then do nothing, the shared boundaries are already
33199  // in charge of performing the connection (it will be required
33200  // to disabled the connection) with the original boundary
33201 
33202  } // else if (!connecting_to_an_overlaped_boundary)
33203 
33204  } // if (!connecting_to_an_split_boundary)
33205 #ifdef OOMPH_HAS_MPI
33206  else
33207  {
33208  // If the boundary was split then we need to look for the vertex
33209  // in the sub-polylines
33210 
33211  // Get the sub-polylines vector
33212  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
33213  this->boundary_subpolylines(dst_bnd_id_initial);
33214 
33215  // Get the number of sub-polylines
33216  const unsigned nsub_poly = tmp_vector_subpolylines.size();
33217 #ifdef PARANOID
33218  if (nsub_poly <= 1)
33219  {
33220  std::ostringstream error_message;
33221  error_message
33222  <<"The boundary (" << dst_bnd_id_initial << ") was "
33223  << "marked to be splitted but\n"
33224  << "there are only ("<<nsub_poly<<") polylines to "
33225  << "represent it.\n";
33226  throw OomphLibError(
33227  error_message.str(),
33228  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33229  OOMPH_EXCEPTION_LOCATION);
33230  } // if (nsub_poly <= 1)
33231 #endif
33232  // We need to check if the boundary is marked to be overlaped by
33233  // a shared boundary, if that is the case we need to check for
33234  // each indivual subpolyline, and for those overlaped by a
33235  // shared polyline do nothing, the shared polylines have already
33236  // deal with these connections
33237 
33238  // ... check if the boundary is marked to be overlaped by
33239  // a shared boundary
33240  if (!connecting_to_an_overlaped_boundary)
33241  {
33242  // The boundary is not overlapped by shared boundaries, we can
33243  // work without checking the subpolylines individually (non of
33244  // them are overlapped by a shared boundary)
33245 
33246  // Look for the vertex number to connect on each of the
33247  // subpolyines
33248  for (unsigned isub = 0; isub < nsub_poly; isub++)
33249  {
33250  // Assign the pointer to the sub-polyline
33251  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33252  // Search for the vertex in the current sub-polyline
33253  found_vertex_on_dst_boundary_initial =
33254  this->get_connected_vertex_number_on_destination_polyline(
33255  poly_to_connect_pt,
33256  src_vertex_coordinates_initial,
33257  n_vertex_connection_initial);
33258 
33259  // If we have found the vertex to connect then break the
33260  // loop
33261  if (found_vertex_on_dst_boundary_initial)
33262  {
33263  // But first save the subpoly number (chunk), that will be
33264  // used to perform the connection
33265  sub_poly_to_connect = isub;
33266  break;
33267  } // if (found_vertex_on_dst_boundary_initial)
33268 
33269  } // for (isub < nsub_poly)
33270 
33271  } // if (!connecting_to_an_overlaped_boundary)
33272  else
33273  {
33274  // If connecting to an overlapped boundary then we ignore the
33275  // subpolylines overlapped by shared boundaries and only look
33276  // on the sub-polylines that are not marked as being overlaped
33277  // by shared boundaries
33278 
33279  // Look for the vertex number to connect on each of the
33280  // subpolyines
33281  for (unsigned isub = 0; isub < nsub_poly; isub++)
33282  {
33283  // Only work with those sub-polylines that are not overlaped
33284  // by shared boundaries
33285  if (!this->
33286  boundary_marked_as_shared_boundary(dst_bnd_id_initial, isub))
33287  {
33288  // Assign the pointer to the sub-polyline
33289  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33290 
33291  // Search for the vertex in the current sub-polyline
33292  found_vertex_on_dst_boundary_initial =
33293  this->get_connected_vertex_number_on_destination_polyline(
33294  poly_to_connect_pt,
33295  src_vertex_coordinates_initial,
33296  n_vertex_connection_initial);
33297 
33298  // Was the vertex found?
33299  if (found_vertex_on_dst_boundary_initial)
33300  {
33301  // But first save the subpoly number (chunk), that will
33302  // be used to perform the connection
33303  sub_poly_to_connect = isub;
33304  break;
33305  } // if (found_vertex_on_dst_boundary_initial)
33306 
33307  } // if (not overlaped by shared boundary)
33308 
33309  } // for (isub < nsub_poly)
33310 
33311  } // else if (!connecting_to_an_overlaped_boundary)
33312 
33313  } // else if (!connecting_to_an_split_boundary)
33314 #endif // #ifdef OOMPH_HAS_MPI
33315 
33316  // If not found it may be that the connection information is
33317  // inverted
33318  if (!found_vertex_on_dst_boundary_initial)
33319  {
33320  // Is the mesh distributed?
33321 #ifdef OOMPH_HAS_MPI
33322  if (this->is_mesh_distributed())
33323  {
33324  // If the mesh is distributed and the vertex number was not
33325  // found, that means that the boundary (or vertex) to connect
33326  // in the destination boundary is not in the current
33327  // processor. In that case suspend the connection
33328  polyline_pt->suspend_initial_vertex_connected();
33329  // Add the polyline to the vector of polylines whose
33330  // connection will be resumed at the end of the adaptation
33331  // process
33332  resume_initial_connection_polyline_pt.push_back(polyline_pt);
33333  // The shared boundaries are marked to connect to the initial
33334  // vertex of the polyline (remember that a shared boundary
33335  // stops adding nodes when it finds a node on an original
33336  // boundary) -- The initial vertex is now a base node
33337  }
33338  else
33339 #endif // #ifdef OOMPH_HAS_MPI
33340  {
33341 #ifdef PARANOID
33342  // If not found then there is a problem with the vertices
33343  // Get the associated boundary id of the current polyline
33344  const unsigned bnd_id = polyline_pt->boundary_id();
33345  std::ostringstream error_message;
33346  error_message
33347  << "INITIAL VERTEX CONNECTION\n"
33348  << "It was not possible to find the associated "
33349  << "vertex number on the destination boundary\n"
33350  << "The current boundary (" << bnd_id << ") is marked to have"
33351  << "a connection at the\nINITIAL vertex ("
33352  << src_vertex_coordinates_initial[0] << ","
33353  << src_vertex_coordinates_initial[1] << ")\n"
33354  << "with boundary ("<< dst_bnd_id_initial << ")\n"
33355  << "This is the list of vertices on the destination boundary\n";
33356  // Get the pointer to the associated polyline by using the
33357  // boundary id
33358  TriangleMeshPolyLine *dst_polyline =
33359  this->boundary_polyline_pt(dst_bnd_id_initial);
33360  // The number of vertices on the destination boundary
33361  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33362  // Loop over the vertices print them
33363  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33364  {
33365  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33366  error_message
33367  << "Vertex#(i): ("
33368  << current_vertex[0] << ", " << current_vertex[1] << ")\n";
33369  }
33370  throw OomphLibError(
33371  error_message.str(),
33372  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33373  OOMPH_EXCEPTION_LOCATION);
33374 #endif
33375 
33376  } // else if (this->is_mesh_distributed())
33377 
33378  } // if (!found_vertex_on_dst_boundary_initial)
33379  else
33380  {
33381  // Set the vertex number on the destination boundary
33382  polyline_pt->initial_vertex_connected_n_vertex() =
33383  n_vertex_connection_initial;
33384 
33385  // Set the chunk number on the destination boundary
33386  polyline_pt->initial_vertex_connected_n_chunk() =
33387  sub_poly_to_connect;
33388 
33389  } // else if (!found_vertex_on_dst_boundary_initial)
33390 
33391  } // if (polyline_pt->is_initial_vertex_connected())
33392 
33393  // ------------------------------------------------------------------
33394  // Is the final vertex connected?
33395  if (polyline_pt->is_final_vertex_connected())
33396  {
33397  // The pointer to the boundary to connect
33398  TriangleMeshPolyLine *poly_to_connect_pt = 0;
33399 
33400  // Get the boundary id of the destination/connected boundary
33401  const unsigned dst_bnd_id_final =
33402  polyline_pt->final_vertex_connected_bnd_id();
33403 
33404  // Get the final vertex on the current boundary
33405  const unsigned tmp_n_vertices = polyline_pt->nvertex();
33406  Vector<double> src_vertex_coordinates_final =
33407  polyline_pt->vertex_coordinate(tmp_n_vertices-1);
33408 
33409 
33410 #ifdef PARANOID
33411  // Is the mesh distributed?
33412 #ifdef OOMPH_HAS_MPI
33413  if (this->is_mesh_distributed())
33414  {
33415  // Get the initial shared boundary id
33416  const unsigned init_shd_bnd_id =
33417  this->initial_shared_boundary_id();
33418  // Is the boundary to connect a shared boundary
33419  if (dst_bnd_id_final >= init_shd_bnd_id)
33420  {
33421  // Get the current polyline original boundary id
33422  const unsigned bnd_id = polyline_pt->boundary_id();
33423  std::ostringstream error_message;
33424  error_message
33425  << "FINAL VERTEX CONNECTION\n"
33426  << "The current original boundary is trying to connect to a\n"
33427  << "shared boundary, this is not allowed. In this case the\n"
33428  << "shared boundary should be the one that connects with the\n"
33429  << "original boundary\n"
33430  << "The current boundary (" << bnd_id << ") is marked to have "
33431  << "a connection at the\nFINAL vertex ("
33432  << src_vertex_coordinates_final[0] << ","
33433  << src_vertex_coordinates_final[1] << ")\n"
33434  << "with boundary ("<< dst_bnd_id_final << ")\n"
33435  << "This is the list of vertices on the destination boundary\n";
33436  // Get the pointer to the associated polyline by using the
33437  // boundary id
33438  TriangleMeshPolyLine *dst_polyline =
33439  this->boundary_polyline_pt(dst_bnd_id_final);
33440  // The number of vertices on the destination boundary
33441  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33442  // Loop over the vertices print them
33443  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33444  {
33445  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33446  error_message
33447  << "Vertex#("<<i<<"): ("
33448  << current_vertex[0] << ", " << current_vertex[1] << ")\n";
33449  }
33450  throw OomphLibError(
33451  error_message.str(),
33452  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33453  OOMPH_EXCEPTION_LOCATION);
33454  } // if (dst_bnd_id_initial >= init_shd_bnd_id)
33455 
33456  } // if (this->is_mesh_distributed())
33457 #endif // #ifdef OOMPH_HAS_MPI
33458 
33459 #endif // #ifdef PARANOID
33460 
33461  // Flag to indicate if the vertex was found on the destination
33462  // boundary
33463  bool found_vertex_on_dst_boundary_final = false;
33464 
33465  // Flag that stores the chunk number to connect (only used in
33466  // distributed meshes)
33467  unsigned sub_poly_to_connect = 0;
33468 
33469  // Store the vertex number on the destination boundary
33470  unsigned n_vertex_connection_final = 0;
33471 
33472  // Flags only used in a distributed mesh
33473  // ----------------------------------------
33474  // Flag to indicate we are trying to connect to an split boundary
33475  bool connecting_to_an_split_boundary = false;
33476 
33477  // Flag to indicate we are trying to connecto to an internal
33478  // boundary that is overlaped by a shared boundary)
33479  bool connecting_to_an_overlaped_boundary = false;
33480 
33481 #ifdef OOMPH_HAS_MPI
33482  if (this->is_mesh_distributed())
33483  {
33484  // We can only connect to an original boundary, check if the
33485  // boundary was splitted during the distribution process to
33486  // consider all the chunks (sub-polylines) of the boundary
33487  if (this->boundary_was_splitted(dst_bnd_id_final))
33488  {
33489  connecting_to_an_split_boundary = true;
33490  } // if (this->boundary_was_splitted(dst_bnd_id_final))
33491 
33492  // Check if the destination boundary, or any of its chunks is
33493  // marked to be overlapped by a shared boundary, if that is the
33494  // case we can only connect to the chunks that are not
33495  // overlapped by shared boundaries (the shared boundaries are in
33496  // charge of generating the connections with original boundaries
33497  // and with themselves)
33498  if (connecting_to_an_split_boundary)
33499  {
33500  // Get the number of chucks that represent the destination
33501  // boundary
33502  const unsigned n_sub_poly =
33503  this->nboundary_subpolylines(dst_bnd_id_final);
33504  // Now loop over the chunks of the destination boundary and if
33505  // any of them is marked to be overlaped by a shared boundary
33506  // then set the flag and break the loop
33507  for (unsigned ii =0; ii < n_sub_poly; ii++)
33508  {
33509  if (this->
33510  boundary_marked_as_shared_boundary(dst_bnd_id_final, ii))
33511  {
33512  // Mark the boundary as being overlaped by a shared
33513  // boundary
33514  connecting_to_an_overlaped_boundary = true;
33515  // Break, no need to look for more overlapings
33516  break;
33517  } // if (boundary_marked_as_shared_boundary(...))
33518  } // for (ii < n_sub_poly)
33519  } // if (connecting_to_an_split_boundary)
33520  else
33521  {
33522  // If not connecting to an split boundary then check if the
33523  // whole destination boundary is overlaped by an internal
33524  // boundary
33525  if (this->
33526  boundary_marked_as_shared_boundary(dst_bnd_id_final, 0))
33527  {
33528  // Mark the boundary as being overlaped by a shared boundary
33529  connecting_to_an_overlaped_boundary = true;
33530  } // if (boundary_marked_as_shared_boundary(...))
33531  } // else if (connecting_to_an_split_boundary)
33532 
33533  } // if (this->is_mesh_distributed())
33534 
33535 #endif // #ifdef OOMPH_HAS_MPI
33536 
33537  // If we are connecting neither to an split boundary nor an
33538  // overlaped boundary then get the pointer to the original
33539  // boundary
33540  if (!(connecting_to_an_split_boundary ||
33541  connecting_to_an_overlaped_boundary))
33542  {
33543  // Get the polyline pointer representing the destination
33544  // boundary
33545  poly_to_connect_pt = this->boundary_polyline_pt(dst_bnd_id_final);
33546  } // else if (NOT split, NOT overlaped)
33547 
33548  // Now look for the vertex number on the destination boundary(ies)
33549  // -- in case that the boundary was split ---
33550 
33551  // Do not check for same orientation, that was previously worked
33552  // by interchanging the connections boundaries (if necessary)
33553 
33554  // If the boundary was not split then ...
33555  if (!connecting_to_an_split_boundary)
33556  {
33557  // ... check if the boundary is marked to be overlaped by
33558  // a shared boundary
33559  if (!connecting_to_an_overlaped_boundary)
33560  {
33561  // If that is not the case then we can safely look for the
33562  // vertex number on the destination boundary
33563  found_vertex_on_dst_boundary_final =
33564  this->get_connected_vertex_number_on_destination_polyline(
33565  poly_to_connect_pt,
33566  src_vertex_coordinates_final,
33567  n_vertex_connection_final);
33568 
33569  } // if (!connecting_to_an_overlaped_boundary)
33570  else
33571  {
33572  // If the whole boundary is marked to be overlaped by a shared
33573  // boundary then do nothing, the shared boundaries are already
33574  // in charge of performing the connection (it will be required
33575  // to disabled the connection) with the original boundary
33576 
33577  } // else if (!connecting_to_an_overlaped_boundary)
33578 
33579  } // if (!connecting_to_an_split_boundary)
33580 #ifdef OOMPH_HAS_MPI
33581  else
33582  {
33583  // If the boundary was split then we need to look for the vertex
33584  // in the sub-polylines
33585 
33586  // Get the sub-polylines vector
33587  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
33588  this->boundary_subpolylines(dst_bnd_id_final);
33589 
33590  // Get the number of sub-polylines
33591  const unsigned nsub_poly = tmp_vector_subpolylines.size();
33592 #ifdef PARANOID
33593  if (nsub_poly <= 1)
33594  {
33595  std::ostringstream error_message;
33596  error_message
33597  <<"The boundary (" << dst_bnd_id_final << ") was "
33598  << "marked to be splitted but\n"
33599  << "there are only ("<<nsub_poly<<") polylines to "
33600  << "represent it.\n";
33601  throw OomphLibError(
33602  error_message.str(),
33603  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33604  OOMPH_EXCEPTION_LOCATION);
33605  } // if (nsub_poly <= 1)
33606 #endif
33607  // We need to check if the boundary is marked to be overlaped by
33608  // a shared boundary, if that is the case we need to check for
33609  // each indivual subpolyline, and for those overlaped by a
33610  // shared polyline do nothing, the shared polylines have already
33611  // deal with these connections
33612 
33613  // ... check if the boundary is marked to be overlaped by
33614  // a shared boundary
33615  if (!connecting_to_an_overlaped_boundary)
33616  {
33617  // The boundary is not overlapped by shared boundaries, we can
33618  // work without checking the subpolylines individually (non of
33619  // them are overlapped by a shared boundary)
33620 
33621  // Look for the vertex number to connect on each of the
33622  // subpolyines
33623  for (unsigned isub = 0; isub < nsub_poly; isub++)
33624  {
33625  // Assign the pointer to the sub-polyline
33626  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33627  // Search for the vertex in the current sub-polyline
33628  found_vertex_on_dst_boundary_final =
33629  this->get_connected_vertex_number_on_destination_polyline(
33630  poly_to_connect_pt,
33631  src_vertex_coordinates_final,
33632  n_vertex_connection_final);
33633 
33634  // If we have found the vertex to connect then break the
33635  // loop
33636  if (found_vertex_on_dst_boundary_final)
33637  {
33638  // But first save the subpoly number (chunk), that will be
33639  // used to perform the connection
33640  sub_poly_to_connect = isub;
33641  break;
33642  } // if (found_vertex_on_dst_boundary_initial)
33643 
33644  } // for (isub < nsub_poly)
33645 
33646  } // if (!connecting_to_an_overlaped_boundary)
33647  else
33648  {
33649  // If connecting to an overlapped boundary then we ignore the
33650  // subpolylines overlapped by shared boundaries and only look
33651  // on the sub-polylines that are not marked as being overlaped
33652  // by shared boundaries
33653 
33654  // Look for the vertex number to connect on each of the
33655  // subpolyines
33656  for (unsigned isub = 0; isub < nsub_poly; isub++)
33657  {
33658  // Only work with those sub-polylines that are not overlaped
33659  // by shared boundaries
33660  if (!this->
33661  boundary_marked_as_shared_boundary(dst_bnd_id_final, isub))
33662  {
33663  // Assign the pointer to the sub-polyline
33664  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33665 
33666  // Search for the vertex in the current sub-polyline
33667  found_vertex_on_dst_boundary_final =
33668  this->get_connected_vertex_number_on_destination_polyline(
33669  poly_to_connect_pt,
33670  src_vertex_coordinates_final,
33671  n_vertex_connection_final);
33672 
33673  // Was the vertex found?
33674  if (found_vertex_on_dst_boundary_final)
33675  {
33676  // But first save the subpoly number (chunk), that will
33677  // be used to perform the connection
33678  sub_poly_to_connect = isub;
33679  break;
33680  } // if (found_vertex_on_dst_boundary_final)
33681 
33682  } // if (not overlaped by shared boundary)
33683 
33684  } // for (isub < nsub_poly)
33685 
33686  } // else if (!connecting_to_an_overlaped_boundary)
33687 
33688  } // else if (!connecting_to_an_split_boundary)
33689 #endif // #ifdef OOMPH_HAS_MPI
33690 
33691  // If not found it may be that the connection information is
33692  // inverted
33693  if (!found_vertex_on_dst_boundary_final)
33694  {
33695  // Is the mesh distributed?
33696 #ifdef OOMPH_HAS_MPI
33697  if (this->is_mesh_distributed())
33698  {
33699  // If the mesh is distributed and the vertex number was not
33700  // found, that means that the boundary (or vertex) to connect
33701  // in the destination boundary is not in the current
33702  // processor. In that suspend the connection
33703  polyline_pt->suspend_final_vertex_connected();
33704  // Add the polyline to the vector of polylines whose
33705  // connection will be resumed at the end of the adaptation
33706  // process
33707  resume_final_connection_polyline_pt.push_back(polyline_pt);
33708  // The shared boundaries are marked to connect to the final
33709  // vertex of the polyline (remember that a shared boundary
33710  // stops adding nodes when it finds a node on an original
33711  // boundary) -- The final vertex is now a base node
33712  } // if (this->is_mesh_distributed())
33713  else
33714 #endif // #ifdef OOMPH_HAS_MPI
33715  {
33716 #ifdef PARANOID
33717  // If not found then there is a problem with the vertices
33718  // Get the associated boundary id of the current polyline
33719  const unsigned bnd_id = polyline_pt->boundary_id();
33720  std::ostringstream error_message;
33721  error_message
33722  << "FINAL VERTEX CONNECTION\n"
33723  << "It was not possible to find the associated "
33724  << "vertex number on the destination boundary\n"
33725  << "The current boundary (" << bnd_id << ") is marked to have "
33726  << "a connection at the\nFINAL vertex ("
33727  << src_vertex_coordinates_final[0] << ","
33728  << src_vertex_coordinates_final[1] << ")\n"
33729  << "with boundary ("<< dst_bnd_id_final << ")\n"
33730  << "This is the list of vertices on the destination boundary\n";
33731  // Get the pointer to the associated polyline by using the
33732  // boundary id
33733  TriangleMeshPolyLine *dst_polyline =
33734  this->boundary_polyline_pt(dst_bnd_id_final);
33735  // The number of vertices on the destination boundary
33736  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33737  // Loop over the vertices print them
33738  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33739  {
33740  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33741  error_message
33742  << "Vertex#("<<i<<"): ("
33743  << current_vertex[0] << ", " << current_vertex[1] << ")\n";
33744  }
33745  throw OomphLibError(
33746  error_message.str(),
33747  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33748  OOMPH_EXCEPTION_LOCATION);
33749 #endif
33750  } // else if (this->is_mesh_distributed())
33751 
33752  } // if (!found_vertex_on_dst_boundary_final)
33753  else
33754  {
33755  // Set the vertex number on the destination boundary
33756  polyline_pt->final_vertex_connected_n_vertex() =
33757  n_vertex_connection_final;
33758 
33759  // Set the chunk number on the destination boundary
33760  polyline_pt->final_vertex_connected_n_chunk() =
33761  sub_poly_to_connect;
33762 
33763  } // else if (!found_vertex_on_dst_boundary_final)
33764 
33765  } // if (polyline_pt->is_final_vertex_connected())
33766 
33767  }
33768 
33769  //=========================================================================
33770  /// \short Resume the boundary connections that may have been
33771  /// suspended because the destination boundary is no part of the
33772  /// domain. The connections are no permanently suspended because if
33773  /// load balance takes place the destination boundary may be part of
33774  /// the new domain representation therefore the connection would
33775  /// exist
33776  //=========================================================================
33777  template<class ELEMENT>
33779  Vector<TriangleMeshPolyLine*> &resume_initial_connection_polyline_pt,
33780  Vector<TriangleMeshPolyLine*> &resume_final_connection_polyline_pt)
33781  {
33782  // Get the number of polylines that require to resume the connection
33783  // at the initial vertex
33784  const unsigned n_initial_poly =
33785  resume_initial_connection_polyline_pt.size();
33786  // Loop over the polylines that require to resume the connection
33787  // at the initial vertex
33788  for (unsigned p = 0; p < n_initial_poly; p++)
33789  {
33790  // Get the polyline
33791  TriangleMeshPolyLine* tmp_poly_pt =
33792  resume_initial_connection_polyline_pt[p];
33793  // Resume the connection with the initial vertex
33794  tmp_poly_pt->resume_initial_vertex_connected();
33795  } // for (p < n_initial_poly)
33796 
33797  // Get the number of polylines that require to resume the connection
33798  // at the final vertex
33799  const unsigned n_final_poly =
33800  resume_final_connection_polyline_pt.size();
33801  // Loop over the polylines that require to resume the connection at
33802  // the final vertex
33803  for (unsigned p = 0; p < n_final_poly; p++)
33804  {
33805  // Get the polyline
33806  TriangleMeshPolyLine* tmp_poly_pt =
33807  resume_final_connection_polyline_pt[p];
33808  // Resume the connection with the final vertex
33809  tmp_poly_pt->resume_final_vertex_connected();
33810  } // for (p < n_final_poly)
33811 
33812  // Clear the storage
33813  resume_initial_connection_polyline_pt.clear();
33814  resume_final_connection_polyline_pt.clear();
33815 
33816  }
33817 
33818 //=========================================================================
33819 /// \short Gets the associated vertex number according to the vertex
33820 /// coordinates on the destination boundary
33821 //=========================================================================
33822 template<class ELEMENT>
33825  Vector<double> &vertex_coordinates,
33826  const unsigned &dst_bnd_id,
33827  unsigned &vertex_number)
33828  {
33829 
33830  bool found_associated_vertex_number = false;
33831 
33832  // Get the pointer to the associated polyline by using the boundary id
33833  TriangleMeshPolyLine *dst_polyline =
33834  this->boundary_polyline_pt(dst_bnd_id);
33835 
33836  const unsigned n_vertices = dst_polyline->nvertex();
33837 
33838  // Loop over the vertices and return the closest vertex
33839  // to the given vertex coordinates
33840  for (unsigned i = 0; i < n_vertices; i++)
33841  {
33842 
33843  Vector<double> current_vertex =
33844  dst_polyline->vertex_coordinate(i);
33845 
33846  double error =
33847  (vertex_coordinates[0] - current_vertex[0])*
33848  (vertex_coordinates[0] - current_vertex[0])
33849  +
33850  (vertex_coordinates[1] - current_vertex[1])*
33851  (vertex_coordinates[1] - current_vertex[1]);
33852 
33853  error = sqrt(error);
33854 
33855  if(error <
33857  {
33858  vertex_number = i;
33859  found_associated_vertex_number = true;
33860  break;
33861  }
33862 
33863  }
33864 
33865  return found_associated_vertex_number;
33866 
33867  }
33868 
33869 //=========================================================================
33870 /// \short Helper function that updates the input polygon's PSLG
33871 /// by using the end-points of elements from FaceMesh(es) that are
33872 /// constructed for the boundaries associated with the segments of the
33873 /// polygon. Optional boolean is used to run it as test only (if
33874 /// true is specified as input) in which case polygon isn't actually
33875 /// modified. Returned boolean indicates if polygon was (or would have
33876 /// been -- if called with check_only=false) changed.
33877 //=========================================================================
33878 template<class ELEMENT>
33881  const bool& check_only)
33882  {
33883 #ifdef PARANOID
33884  // If the mesh is marked as distributed this method can not be
33885  // called since there is no guarantee of creating (distributed)
33886  // meshes that match in the number and position of nodes at their
33887  // shared boundaries. The only exececption is when called with
33888  // check_only=true, since no boundary updating is performed
33889  if (this->is_mesh_distributed() && !check_only)
33890  {
33891  std::stringstream error_message;
33892  error_message
33893  << "The updating of polygons of a distributed mesh can ONLY be\n"
33894  << "performed using the element's area associated to the halo(ed)\n"
33895  << "elements.\n"
33896  << "1) Make sure you have enabled the parallel mesh adaptation\n"
33897  << "option if you are working with a distributed mesh, OR\n"
33898  << "2) Make sure to call the update_..._using_elements_area() methods\n"
33899  << "if the mesh is marked as distributed\n\n";
33900  throw OomphLibError(error_message.str(),
33901  OOMPH_CURRENT_FUNCTION,
33902  OOMPH_EXCEPTION_LOCATION);
33903  } // if (this->is_mesh_distributed())
33904 #endif
33905 
33906  // Boolean that indicates whether an actual update of the polygon
33907  // was performed or not
33908  bool unrefinement_was_performed=false;
33909  bool refinement_was_performed=false;
33910  bool max_length_applied = false;
33911 
33912  //Loop over the number of polylines
33913  const unsigned n_polyline = polygon_pt->npolyline();
33914 
33915  // Get face mesh representation of all polylines, possibly
33916  // with segments re-distributed to maintain an approximately
33917  // even sub-division of the polygon
33918  Vector<Mesh*> face_mesh_pt;
33919  get_face_mesh_representation(polygon_pt,face_mesh_pt);
33920 
33921  // Create vertices for the polylines by using the vertices
33922  // of the FaceElements
33923  Vector<double> vertex_coord(3); // zeta,x,y
33924  Vector<double> bound_left(1);
33925  Vector<double> bound_right(1);
33926 
33927  for(unsigned p=0;p<n_polyline;p++)
33928  {
33929  // Set of coordinates that will be placed on the boundary
33930  // Set entries are ordered on first entry in vector which stores
33931  // the boundary coordinate so the vertices come out in order!
33932  std::set<Vector<double> > vertex_nodes;
33933 
33934  //Get the boundary id
33935  const unsigned bound = polygon_pt->curve_section_pt(p)->boundary_id();
33936 
33937  // Get the chunk number
33938  const unsigned chunk = polygon_pt->curve_section_pt(p)->boundary_chunk();
33939 
33940  // Loop over the face elements (ordered) and add their vertices
33941  unsigned n_face_element = face_mesh_pt[p]->nelement();
33942  for(unsigned e=0;e<n_face_element;++e)
33943  {
33944  FiniteElement* el_pt = face_mesh_pt[p]->finite_element_pt(e);
33945 
33946 #ifdef OOMPH_HAS_MPI
33947  // Only work with non-halo elements if the mesh is distributed
33948  if (this->is_mesh_distributed() && el_pt->is_halo()) {continue;}
33949 #endif
33950 
33951  unsigned n_node = el_pt->nnode();
33952 
33953  //Add the left-hand node to the set:
33954 
33955  // Boundary coordinate
33956  el_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
33957  vertex_coord[0] = bound_left[0];
33958 
33959  // Actual coordinates
33960  for(unsigned i=0;i<2;i++)
33961  {
33962  vertex_coord[i+1] = el_pt->node_pt(0)->x(i);
33963  }
33964  vertex_nodes.insert(vertex_coord);
33965 
33966  //Add the right-hand nodes to the set:
33967 
33968  //Boundary coordinate
33969  el_pt->node_pt(n_node-1)->
33970  get_coordinates_on_boundary(bound,bound_right);
33971  vertex_coord[0] = bound_right[0];
33972 
33973  // Actual coordinates
33974  for(unsigned i=0;i<2;i++)
33975  {
33976  vertex_coord[i+1] = el_pt->node_pt(n_node-1)->x(i);
33977  }
33978  vertex_nodes.insert(vertex_coord);
33979 
33980  }
33981 
33982  // Now turn into vector for ease of handling...
33983  unsigned n_poly_vertex = vertex_nodes.size();
33984  Vector<Vector<double> > tmp_vector_vertex_node(n_poly_vertex);
33985  unsigned count=0;
33986  for(std::set<Vector<double> >::iterator it = vertex_nodes.begin();
33987  it!=vertex_nodes.end();++it)
33988  {
33989  tmp_vector_vertex_node[count].resize(3);
33990  tmp_vector_vertex_node[count][0] = (*it)[0];
33991  tmp_vector_vertex_node[count][1] = (*it)[1];
33992  tmp_vector_vertex_node[count][2] = (*it)[2];
33993  ++count;
33994  }
33995 
33996  // Size of the vector
33997  unsigned n_vertex=tmp_vector_vertex_node.size();
33998 
33999  // Tolerance below which the middle point can be deleted
34000  // (ratio of deflection to element length)
34001  double unrefinement_tolerance=
34002  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
34003 
34004  //------------------------------------------------------
34005  // Unrefinement
34006  //------------------------------------------------------
34007  if (unrefinement_tolerance>0.0 && n_vertex>=3)
34008  {
34009  unrefinement_was_performed =
34010  unrefine_boundary(bound, chunk, tmp_vector_vertex_node,
34011  unrefinement_tolerance, check_only);
34012 
34013  // In this case the "unrefinement_was_performed" variable
34014  // tell us if the update had been performed when calling
34015  // with check_oly=false
34016  if (check_only && unrefinement_was_performed)
34017  {
34018  // Cleanup (but only the elements -- the nodes still exist in
34019  // the bulk mesh!
34020  for(unsigned p=0;p<n_polyline;p++)
34021  {
34022  face_mesh_pt[p]->flush_node_storage();
34023  delete face_mesh_pt[p];
34024  }
34025  return true;
34026  }
34027 
34028  } // end of unrefinement
34029 
34030  // Do not perform refinement if there are no more than two vertices
34031  // New size of the vector
34032  n_vertex=tmp_vector_vertex_node.size();
34033 
34034  //------------------------------------------------
34035  // Refinement
34036  //------------------------------------------------
34037  double refinement_tolerance=
34038  polygon_pt->polyline_pt(p)->refinement_tolerance();
34039  if (refinement_tolerance>0.0 && n_vertex >= 2)
34040  {
34041  refinement_was_performed =
34042  refine_boundary(face_mesh_pt[p], tmp_vector_vertex_node,
34043  refinement_tolerance, check_only);
34044 
34045  // In this case the "refinement_was_performed" variable
34046  // tell us if the update had been performed when calling
34047  // with check_only=false
34048  if (check_only && refinement_was_performed)
34049  {
34050  // Cleanup (but only the elements -- the nodes still exist in
34051  // the bulk mesh!
34052  for(unsigned p=0;p<n_polyline;p++)
34053  {
34054  face_mesh_pt[p]->flush_node_storage();
34055  delete face_mesh_pt[p];
34056  }
34057  return true;
34058  }
34059 
34060  } // end refinement
34061 
34062  // Do not perform maximum length constraint if there are no more than
34063  // two vertices
34064  // New size of the vector
34065  n_vertex=tmp_vector_vertex_node.size();
34066 
34067  //------------------------------------------------
34068  // Maximum length constrait
34069  //-----------------------------------------------
34070  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
34071  if (maximum_length > 0.0 && n_vertex >= 2)
34072  {
34073  max_length_applied =
34074  apply_max_length_constraint(face_mesh_pt[p],
34075  tmp_vector_vertex_node,
34076  maximum_length);
34077 
34078  // In this case the max length criteria was applied, check if
34079  // check_only=false
34080  if (check_only && max_length_applied)
34081  {
34082  // Cleanup (but only the elements -- the nodes still exist in
34083  // the bulk mesh!
34084  for(unsigned p=0;p<n_polyline;p++)
34085  {
34086  face_mesh_pt[p]->flush_node_storage();
34087  delete face_mesh_pt[p];
34088  }
34089  return true;
34090  }
34091 
34092  }
34093 
34094  // For further processing the three-dimensional vector
34095  // has to be reduced to a two-dimensional vector
34096  n_vertex=tmp_vector_vertex_node.size();
34097  Vector<Vector<double> > vector_vertex_node(n_vertex);
34098 
34099  for(unsigned i=0;i<n_vertex;i++)
34100  {
34101  vector_vertex_node[i].resize(2);
34102  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
34103  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
34104  }
34105 
34106 #ifdef OOMPH_HAS_MPI
34107  // Only perform this checking if the mesh is not distributed. When
34108  // the mesh is distributed the polylines continuity is addressed in
34109  // the sort_polylines_helper() method
34110  if (!this->is_mesh_distributed())
34111 #endif
34112  {
34113  if ( (p > 0) && !check_only )
34114  {
34115  //Final end point of previous line
34116  Vector<double> final_vertex_of_previous_segment;
34117  unsigned n_prev_vertex =
34118  polygon_pt->curve_section_pt(p-1)->nvertex();
34119  final_vertex_of_previous_segment =
34120  polygon_pt->polyline_pt(p-1)->
34121  vertex_coordinate(n_prev_vertex-1);
34122 
34123  unsigned prev_seg_boundary_id =
34124  polygon_pt->curve_section_pt(p-1)->boundary_id();
34125 
34126  //Find the error between the final vertex of the previous
34127  //line and the first vertex of the current line
34128  double error = 0.0;
34129  for(unsigned i=0;i<2;i++)
34130  {
34131  const double dist =
34132  final_vertex_of_previous_segment[i] -
34133  (*vector_vertex_node.begin())[i];
34134  error += dist*dist;
34135  }
34136  error = sqrt(error);
34137 
34138  //If the error is bigger than the tolerance then
34139  //we probably need to reverse, but better check
34141  {
34142  //Find the error between the final vertex of the previous
34143  //line and the last vertex of the current line
34144  double rev_error = 0.0;
34145  for(unsigned i=0;i<2;i++)
34146  {
34147  const double dist =
34148  final_vertex_of_previous_segment[i] -
34149  (*--vector_vertex_node.end())[i];
34150  rev_error += dist*dist;
34151  }
34152  rev_error = sqrt(rev_error);
34153 
34154  if(rev_error >
34156  {
34157  // It could be possible that the first segment be reversed and we
34158  // did not notice it because this check does not apply for the
34159  // first segment. We can verify if the first segment is reversed
34160  // by using the vertex number 1
34161  if (p == 1)
34162  {
34163 
34164  //Initial end point of previous line
34165  Vector<double> initial_vertex_of_previous_segment;
34166 
34167  initial_vertex_of_previous_segment =
34168  polygon_pt->polyline_pt(p-1)->
34169  vertex_coordinate(0);
34170 
34171  unsigned prev_seg_boundary_id =
34172  polygon_pt->curve_section_pt(p-1)->boundary_id();
34173 
34174  //Find the error between the initial vertex of the previous
34175  //line and the first vertex of the current line
34176  double error = 0.0;
34177  for(unsigned i=0;i<2;i++)
34178  {
34179  const double dist =
34180  initial_vertex_of_previous_segment[i] -
34181  (*vector_vertex_node.begin())[i];
34182  error += dist*dist;
34183  }
34184  error = sqrt(error); // Reversed only the previous one
34185 
34186  //If the error is bigger than the tolerance then
34187  //we probably need to reverse, but better check
34189  {
34190  //Find the error between the final vertex of the previous
34191  //line and the last vertex of the current line
34192  double rev_error = 0.0;
34193  for(unsigned i=0;i<2;i++)
34194  {
34195  const double dist =
34196  initial_vertex_of_previous_segment[i] -
34197  (*--vector_vertex_node.end())[i];
34198  rev_error += dist*dist;
34199  }
34200  rev_error = sqrt(rev_error); // Reversed both the current one and
34201  // the previous one
34202 
34203  if (rev_error >
34205  {
34206  std::ostringstream error_stream;
34207  error_stream
34208  <<"The distance between the first node of the current\n"
34209  <<"line segment (boundary " << bound << ") and either end of "
34210  << "the previous line segment\n"
34211  << "(boundary " << prev_seg_boundary_id << ") is bigger than "
34212  << "the desired tolerance " <<
34214  << "This suggests that the polylines defining the polygonal\n"
34215  << "representation are not properly ordered.\n"
34216  << "Fail on last vertex of polyline: ("
34217  << prev_seg_boundary_id<< ") and\nfirst vertex of polyline ("
34218  << bound << ").\nThis should have failed when first trying to "
34219  << "construct the\npolygon.\n";
34220  throw OomphLibError(error_stream.str(),
34221  OOMPH_CURRENT_FUNCTION,
34222  OOMPH_EXCEPTION_LOCATION);
34223 
34224  }
34225  else
34226  {
34227  // Reverse both
34228  // Reverse the current vector to line up with the previous one
34229  std::reverse(vector_vertex_node.begin(),
34230  vector_vertex_node.end());
34231 
34232  polygon_pt->polyline_pt(p-1)->reverse();
34233  }
34234  }
34235  else
34236  {
34237  // Reverse the previous one
34238  polygon_pt->polyline_pt(p-1)->reverse();
34239  }
34240 
34241  } // if p == 1
34242  else
34243  {
34244  std::ostringstream error_stream;
34245  error_stream
34246  <<"The distance between the first node of the current\n"
34247  <<"line segment (boundary " << bound << ") and either end of "
34248  << "the previous line segment\n"
34249  << "(boundary " << prev_seg_boundary_id << ") is bigger than the "
34250  << "desired tolerance " <<
34252  <<"This suggests that the polylines defining the polygonal\n"
34253  <<"representation are not properly ordered.\n"
34254  << "Fail on last vertex of polyline: (" << prev_seg_boundary_id
34255  << ") and\nfirst vertex of polyline (" << bound << ").\n"
34256  << "This should have failed when first trying to construct the\n"
34257  << "polygon.\n";
34258  throw OomphLibError(error_stream.str(),
34259  OOMPH_CURRENT_FUNCTION,
34260  OOMPH_EXCEPTION_LOCATION);
34261  }
34262  }
34263  else
34264  {
34265  //Reverse the current vector to line up with the previous one
34266  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
34267  }
34268 
34269  } // first error
34270  } // p > 0
34271  } // is mesh not distributed?
34272 
34273  if(!check_only)
34274  {
34275  // Now update the polyline according to the new vertices
34276  // The new one representation
34277  TriangleMeshPolyLine *tmp_polyline_pt =
34278  new TriangleMeshPolyLine(vector_vertex_node,bound);
34279 
34280  // Create a temporal "curve section" version of the recently created
34281  // polyline
34282  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
34283 
34284  // Establish refinement and unrefinement tolerance
34285  tmp_polyline_pt->set_unrefinement_tolerance(
34286  unrefinement_tolerance);
34287  tmp_polyline_pt->set_refinement_tolerance(
34288  refinement_tolerance);
34289 
34290  // Establish the maximum length constraint
34291  tmp_polyline_pt->set_maximum_length(maximum_length);
34292 
34293  // We pass the connection information from the old polyline to
34294  // the new one
34295  this->copy_connection_information(polygon_pt->polyline_pt(p),
34296  tmp_curve_section_pt);
34297 
34298  //Now update the polyline according to the new vertices but
34299  //first check if the object is allowed to delete the representation
34300  //or if it should be done by other object
34301  bool delete_it_on_destructor = false;
34302 
34303  std::set<TriangleMeshCurveSection*>::iterator it =
34304  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
34305 
34306  if (it!=this->Free_curve_section_pt.end())
34307  {
34308  this->Free_curve_section_pt.erase(it);
34309  delete polygon_pt->curve_section_pt(p);
34310  delete_it_on_destructor = true;
34311  }
34312 
34313  // ------------------------------------------------------------
34314  // Copying the new representation
34315  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
34316 
34317  // Update the Boundary - Polyline map
34318  this->Boundary_curve_section_pt[bound] = polygon_pt->curve_section_pt(p);
34319 
34320  if (delete_it_on_destructor)
34321  {
34322  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
34323  }
34324 
34325  } // if(!check_only)
34326 
34327  } // for (p < n_polyline)
34328 
34329  // Cleanup (but only the elements -- the nodes still exist in
34330  // the bulk mesh!
34331  for(unsigned p=0;p<n_polyline;p++)
34332  {
34333  face_mesh_pt[p]->flush_node_storage();
34334  delete face_mesh_pt[p];
34335  }
34336 
34337  if(check_only)
34338  {
34339  // if we end up all the way down here, no update of the internal boundaries
34340  // is necessary (in case we only check)
34341  return false;
34342  }
34343  else
34344  {
34345  // if we not only check, but actually perform the update and end up
34346  // all the way down here then we indicate whether an update was performed
34347  // or not
34348  return (unrefinement_was_performed ||
34349  refinement_was_performed ||
34350  max_length_applied);
34351  }
34352 
34353  }
34354 
34355 //=========================================================================
34356 /// \short Helper function that updates the input open curve by using
34357 /// end-points of elements from FaceMesh(es) that are constructed for the
34358 /// boundaries associated with the polylines. Optional boolean is used to
34359 /// run it as test only (if true is specified as input) in which case the
34360 /// polylines are not actually modified. Returned boolean indicates if
34361 /// polylines were (or would have been -- if called with check_only=false)
34362 /// changed.
34363 //=========================================================================
34364 template<class ELEMENT>
34367  const bool& check_only)
34368  {
34369 #ifdef PARANOID
34370  // If the mesh is marked as distributed this method can not be
34371  // called since there is no guarantee of creating (distributed)
34372  // meshes that match in the number and position of nodes at their
34373  // shared boundaries. The only exececption is when called with
34374  // check_only=true, since no boundary updating is performed
34375  if (this->is_mesh_distributed() && !check_only)
34376  {
34377  std::stringstream error_message;
34378  error_message
34379  << "The updating of open curves of a distributed mesh can ONLY be\n"
34380  << "performed using the element's area associated to the halo(ed)\n"
34381  << "elements.\n"
34382  << "1) Make sure you have enabled the parallel mesh adaptation\n"
34383  << "option if you are working with a distributed mesh, OR\n"
34384  << "2) Make sure to call the update_..._using_elements_area() methods\n"
34385  << "if the mesh is marked as distributed\n\n";
34386  throw OomphLibError(error_message.str(),
34387  OOMPH_CURRENT_FUNCTION,
34388  OOMPH_EXCEPTION_LOCATION);
34389  } // if (this->is_mesh_distributed())
34390 #endif
34391 
34392  // Boolean that indicates whether an actual update of the polylines
34393  // were performed or not
34394  bool unrefinement_was_performed=false;
34395  bool refinement_was_performed=false;
34396  bool max_length_applied = false;
34397 
34398  //Loop over the number of polylines
34399  const unsigned n_polyline = open_polyline_pt->ncurve_section();
34400 
34401  // Get face mesh representation of all polylines, possibly
34402  // with segments re-distributed to maintain an approximately
34403  // even sub-division of the polygon
34404  Vector<Mesh*> face_mesh_pt;
34405  get_face_mesh_representation(open_polyline_pt, face_mesh_pt);
34406 
34407  // Create vertices for the polylines by using the vertices
34408  // of the FaceElements
34409  Vector<double> vertex_coord(3); // zeta,x,y
34410  Vector<double> bound_left(1);
34411  Vector<double> bound_right(1);
34412 
34413  for(unsigned p=0;p<n_polyline;p++)
34414  {
34415  // Set of coordinates that will be placed on the boundary
34416  // Set entries are ordered on first entry in vector which stores
34417  // the boundary coordinate so the vertices come out in order!
34418  std::set<Vector<double> > vertex_nodes;
34419 
34420  //Get the boundary id
34421  const unsigned bound =
34422  open_polyline_pt->curve_section_pt(p)->boundary_id();
34423 
34424  // Get the chunk number
34425  const unsigned chunk =
34426  open_polyline_pt->curve_section_pt(p)->boundary_chunk();
34427 
34428  // Loop over the face elements (ordered) and add their vertices
34429  unsigned n_face_element = face_mesh_pt[p]->nelement();
34430 
34431  //n_count = 0;
34432  for(unsigned e=0;e<n_face_element;++e)
34433  {
34434  FiniteElement* el_pt = face_mesh_pt[p]->finite_element_pt(e);
34435  unsigned n_node = el_pt->nnode();
34436 
34437  //Add the left-hand node to the set:
34438 
34439  // Boundary coordinate
34440  el_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
34441  vertex_coord[0] = bound_left[0];
34442 
34443  // Actual coordinates
34444  for(unsigned i=0;i<2;i++)
34445  {
34446  vertex_coord[i+1] = el_pt->node_pt(0)->x(i);
34447  }
34448  vertex_nodes.insert(vertex_coord);
34449 
34450  //Add the right-hand nodes to the set:
34451 
34452  //Boundary coordinate
34453  el_pt->node_pt(n_node-1)->get_coordinates_on_boundary(bound,bound_right);
34454  vertex_coord[0] = bound_right[0];
34455 
34456  // Actual coordinates
34457  for(unsigned i=0;i<2;i++)
34458  {
34459  vertex_coord[i+1] = el_pt->node_pt(n_node-1)->x(i);
34460  }
34461  vertex_nodes.insert(vertex_coord);
34462 
34463  }
34464 
34465  // Now turn into vector for ease of handling...
34466  unsigned n_poly_vertex = vertex_nodes.size();
34467  Vector<Vector<double> > tmp_vector_vertex_node(n_poly_vertex);
34468  unsigned count=0;
34469  for(std::set<Vector<double> >::iterator it = vertex_nodes.begin();
34470  it!=vertex_nodes.end();++it)
34471  {
34472  tmp_vector_vertex_node[count].resize(3);
34473  tmp_vector_vertex_node[count][0] = (*it)[0];
34474  tmp_vector_vertex_node[count][1] = (*it)[1];
34475  tmp_vector_vertex_node[count][2] = (*it)[2];
34476  ++count;
34477  }
34478 
34479  // Size of the vector
34480  unsigned n_vertex=tmp_vector_vertex_node.size();
34481 
34482  // Tolerance below which the middle point can be deleted
34483  // (ratio of deflection to element length)
34484  double unrefinement_tolerance=
34485  open_polyline_pt->polyline_pt(p)->unrefinement_tolerance();
34486 
34487  //------------------------------------------------------
34488  // Unrefinement
34489  //------------------------------------------------------
34490  if (unrefinement_tolerance>0.0 && n_vertex>=3)
34491  {
34492  unrefinement_was_performed =
34493  unrefine_boundary(bound, chunk, tmp_vector_vertex_node,
34494  unrefinement_tolerance, check_only);
34495 
34496  // In this case the unrefinement_was_performed variable actually
34497  // tell us if the update had been performed when calling
34498  // with check_only=false
34499  if (check_only && unrefinement_was_performed)
34500  {
34501  // Cleanup (but only the elements -- the nodes still exist in
34502  // the bulk mesh!
34503  for(unsigned p=0;p<n_polyline;p++)
34504  {
34505  face_mesh_pt[p]->flush_node_storage();
34506  delete face_mesh_pt[p];
34507  }
34508  return true;
34509  }
34510 
34511  } // end of unrefinement
34512 
34513  // Do not perform refinement if there are no more than two vertices
34514  // (open curve version)
34515  // New size of the vector
34516  n_vertex=tmp_vector_vertex_node.size();
34517 
34518  //------------------------------------------------
34519  /// Refinement
34520  //------------------------------------------------
34521  double refinement_tolerance=
34522  open_polyline_pt->polyline_pt(p)->refinement_tolerance();
34523  if (refinement_tolerance>0.0 && n_vertex >= 2)
34524  {
34525  refinement_was_performed =
34526  refine_boundary(face_mesh_pt[p], tmp_vector_vertex_node,
34527  refinement_tolerance, check_only);
34528 
34529  // In this case the unrefinement_was_performed variable actually
34530  // tell us if the update had been performed when calling
34531  // with check_only=false
34532  if (check_only && refinement_was_performed)
34533  {
34534  // Cleanup (but only the elements -- the nodes still exist in
34535  // the bulk mesh!
34536  for(unsigned p=0;p<n_polyline;p++)
34537  {
34538  face_mesh_pt[p]->flush_node_storage();
34539  delete face_mesh_pt[p];
34540  }
34541  return true;
34542  }
34543 
34544  } // end refinement
34545 
34546  // Do not perform maximum length constraint if there are no more than
34547  // two vertices
34548  // New size of the vector
34549  n_vertex=tmp_vector_vertex_node.size();
34550 
34551  //------------------------------------------------
34552  // Maximum length constraint
34553  //-----------------------------------------------
34554  double maximum_length = open_polyline_pt->polyline_pt(p)->maximum_length();
34555  if (maximum_length > 0.0 && n_vertex >= 2)
34556  {
34557  bool max_length_applied = false;
34558  max_length_applied =
34559  apply_max_length_constraint(face_mesh_pt[p],
34560  tmp_vector_vertex_node,
34561  maximum_length);
34562 
34563  // In this case the max length criteria was applied, check if
34564  // check_only=false
34565  if (check_only && max_length_applied)
34566  {
34567  // Cleanup (but only the elements -- the nodes still exist in
34568  // the bulk mesh!
34569  for(unsigned p=0;p<n_polyline;p++)
34570  {
34571  face_mesh_pt[p]->flush_node_storage();
34572  delete face_mesh_pt[p];
34573  }
34574  return true;
34575  }
34576 
34577  }
34578 
34579  // For further processing the three-dimensional vector
34580  // has to be reduced to a two-dimensional vector
34581  n_vertex=tmp_vector_vertex_node.size();
34582  Vector<Vector<double> > vector_vertex_node(n_vertex);
34583 
34584  for(unsigned i=0;i<n_vertex;i++)
34585  {
34586  vector_vertex_node[i].resize(2);
34587  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
34588  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
34589  }
34590 
34591 #ifdef OOMPH_HAS_MPI
34592  // Only perform this checking if the mesh is not distributed. When
34593  // the mesh is distributed the polylines continuity is addressed
34594  // in the sort_polylines_helper() method
34595  if (!this->is_mesh_distributed())
34596 #endif
34597  {
34598  //Check whether the segments are continguous (first vertex of this
34599  //segment is equal to last vertex of previous segment).
34600  //If not, we should reverse the order of the current segment.
34601  //This check only applies for segments other than the first.
34602  //We only bother with this check, if we actually perform an update
34603  //of the polyline, i.e. if it's not only a check
34604  if( (p > 0) && !check_only )
34605  {
34606  //Final end point of previous line
34607  Vector<double> final_vertex_of_previous_segment;
34608  open_polyline_pt->polyline_pt(p-1)->
34609  final_vertex_coordinate(final_vertex_of_previous_segment);
34610 
34611  unsigned prev_seg_boundary_id =
34612  open_polyline_pt->curve_section_pt(p-1)->boundary_id();
34613 
34614  //Find the error between the final vertex of the previous
34615  //line and the first vertex of the current line
34616  double error = 0.0;
34617  for(unsigned i=0;i<2;i++)
34618  {
34619  const double dist =
34620  final_vertex_of_previous_segment[i] -
34621  (*vector_vertex_node.begin())[i];
34622  error += dist*dist;
34623  }
34624  error = sqrt(error);
34625 
34626  //If the error is bigger than the tolerance then
34627  //we probably need to reverse, but better check
34629  {
34630  //Find the error between the final vertex of the previous
34631  //line and the first vertex of the current line
34632  error = 0.0;
34633  for(unsigned i=0;i<2;i++)
34634  {
34635  const double dist =
34636  final_vertex_of_previous_segment[i] -
34637  (*--vector_vertex_node.end())[i];
34638  error += dist*dist;
34639  }
34640  error = sqrt(error);
34641 
34643  {
34644  // It could be possible that the first segment be reversed
34645  // and we did not notice it because this check does not
34646  // apply for the first segment. We can verify if the first
34647  // segment is reversed by using the vertex number 1
34648  if (p == 1)
34649  {
34650  // If no found it is possible that the previous polyline
34651  // be reversed Check for that case Initial point of
34652  // previous line
34653  Vector<double> initial_vertex_of_previous_segment;
34654  open_polyline_pt->polyline_pt(p-1)->
34655  initial_vertex_coordinate(initial_vertex_of_previous_segment);
34656 
34657  //Find the error between the initial vertex of the previous
34658  //line and the first vertex of the current line
34659  error = 0.0;
34660  for(unsigned i=0;i<2;i++)
34661  {
34662  const double dist =
34663  initial_vertex_of_previous_segment[i] -
34664  (*vector_vertex_node.begin())[i];
34665  error += dist*dist;
34666  }
34667  error = sqrt(error);
34668 
34669  //If the error is bigger than the tolerance then
34670  //we probably need to reverse, but better check
34672  {
34673  //Find the error between the final vertex of the previous
34674  //line and the first vertex of the current line
34675  error = 0.0;
34676  for(unsigned i=0;i<2;i++)
34677  {
34678  const double dist =
34679  initial_vertex_of_previous_segment[i] -
34680  (*--vector_vertex_node.end())[i];
34681  error += dist*dist;
34682  }
34683  error = sqrt(error);
34684 
34685  if(error >
34687  {
34688  std::ostringstream error_stream;
34689  error_stream
34690  <<"The distance between the first node of the current\n"
34691  <<"line segment (boundary " << bound
34692  <<") and either end of the previous line segment\n"
34693  <<"(boundary " << prev_seg_boundary_id << ") is bigger than "
34694  <<"the desired tolerance " <<
34696  <<"This suggests that the polylines defining the open "
34697  << "curve\n"
34698  <<"representation are not properly ordered.\n"
34699  <<"Fail on last vertex of polyline: ("
34700  << prev_seg_boundary_id
34701  <<") and\nfirst vertex of polyline (" << bound << ").\n"
34702  <<"This should have failed when first trying to construct\n"
34703  <<"the open curve.\n";
34704  throw OomphLibError(error_stream.str(),
34705  OOMPH_CURRENT_FUNCTION,
34706  OOMPH_EXCEPTION_LOCATION);
34707  }
34708  else // We have to reverse both
34709  {
34710  // First reverse the previous polyline
34711  open_polyline_pt->polyline_pt(p-1)->reverse();
34712  // Then reverse the current polyline
34713  std::reverse(vector_vertex_node.begin(),
34714  vector_vertex_node.end());
34715  }
34716  }
34717  else
34718  {
34719  // Reverse the previous polyline only
34720  open_polyline_pt->polyline_pt(p-1)->reverse();
34721  }
34722  } // if (p == 1)
34723  else
34724  {
34725  std::ostringstream error_stream;
34726  error_stream
34727  << "The distance between the first node of the current\n"
34728  << "line segment (boundary " << bound << ") and either end of "
34729  << "the previous line segment\n"
34730  << "(boundary "<<prev_seg_boundary_id<<") is bigger than the "
34731  << "desired tolerance " <<
34733  <<"This suggests that the polylines defining the polygonal\n"
34734  <<"representation are not properly ordered.\n"
34735  << "Fail on last vertex of polyline: ("<<prev_seg_boundary_id
34736  << ") and\nfirst vertex of polyline ("<<bound<<").\n"
34737  << "This should have failed when first trying to construct the\n"
34738  << "polygon.\n";
34739  throw OomphLibError(error_stream.str(),
34740  OOMPH_CURRENT_FUNCTION,
34741  OOMPH_EXCEPTION_LOCATION);
34742  }
34743  }
34744  else
34745  {
34746  //Reverse the current vector to line up with the previous one
34747  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
34748  }
34749 
34750  }
34751 
34752  } // if p > 0
34753 
34754  } // is mesh not distributed?
34755 
34756  if(!check_only)
34757  {
34758  // Now update the polyline according to the new vertices The new
34759  // one representation
34760  TriangleMeshPolyLine *tmp_polyline =
34761  new TriangleMeshPolyLine(vector_vertex_node, bound);
34762 
34763  // Create a temporal "curve section" version of the recently
34764  // created polyline
34765  TriangleMeshCurveSection *tmp_curve_section = tmp_polyline;
34766 
34767  // Copy the unrefinement and refinement information
34768  tmp_polyline->set_unrefinement_tolerance(
34769  unrefinement_tolerance);
34770  tmp_polyline->set_refinement_tolerance(
34771  refinement_tolerance);
34772 
34773  // Establish the maximum length constraint
34774  tmp_polyline->set_maximum_length(maximum_length);
34775 
34776  // Pass the connection information from the old polyline to the
34777  // new one
34778  this->copy_connection_information(open_polyline_pt->polyline_pt(p),
34779  tmp_curve_section);
34780 
34781  std::set<TriangleMeshCurveSection*>::iterator it =
34782  this->Free_curve_section_pt.find(open_polyline_pt->curve_section_pt(p));
34783 
34784  bool delete_it_on_destructor = false;
34785 
34786  if (it!=this->Free_curve_section_pt.end())
34787  {
34788  // Free previous representation only if you created
34789  this->Free_curve_section_pt.erase(it);
34790  delete open_polyline_pt->curve_section_pt(p);
34791  delete_it_on_destructor = true;
34792  }
34793 
34794  // *****************************************************************
34795  // Copying the new representation
34796  open_polyline_pt->curve_section_pt(p) = tmp_polyline;
34797 
34798  // Update the Boundary <--> PolyLine map
34799  this->Boundary_curve_section_pt[bound] =
34800  open_polyline_pt->curve_section_pt(p);
34801 
34802  if (delete_it_on_destructor)
34803  {
34804  this->Free_curve_section_pt.insert(
34805  open_polyline_pt->curve_section_pt(p));
34806  }
34807 
34808  } // if(!check_only)
34809 
34810  } // n_polylines
34811 
34812  // Cleanup (but only the elements -- the nodes still exist in
34813  // the bulk mesh!
34814  for(unsigned p=0;p<n_polyline;p++)
34815  {
34816  face_mesh_pt[p]->flush_node_storage();
34817  delete face_mesh_pt[p];
34818  }
34819 
34820  if(check_only)
34821  {
34822  // if we end up all the way down here, no update of the internal
34823  // boundaries is necessary (in case we only check)
34824  return false;
34825  }
34826  else
34827  {
34828  // if we not only check, but actually perform the update and end
34829  // up all the way down here then we indicate whether an update was
34830  // performed or not
34831  return (unrefinement_was_performed ||
34832  refinement_was_performed ||
34833  max_length_applied);
34834  }
34835 
34836  }
34837 
34838 //=========================================================================
34839 /// \short Helper function that performs the unrefinement process
34840 /// on the specified boundary by using the provided vertices
34841 /// representation. Optional boolean is used to run it as test only (if
34842 /// true is specified as input) in which case vertex coordinates aren't
34843 /// actually modified. Returned boolean indicates if polyline was (or
34844 /// would have been -- if called with check_only=false) changed.
34845 //=========================================================================
34846 template<class ELEMENT>
34848 unrefine_boundary(const unsigned &b,
34849  const unsigned &c,
34850  Vector<Vector<double> > &vector_bnd_vertices,
34851  double &unrefinement_tolerance,
34852  const bool &check_only)
34853  {
34854  // Store the vertices not allowed for deletion
34855  std::set<Vector<double> > no_delete_vertex;
34856 
34857  // Does the boundary receives connections?
34858  const bool boundary_receive_connections =
34859  this->boundary_connections(b, c, no_delete_vertex);
34860 
34861  // Boolean that indicates whether an actual update of the vertex
34862  // coordinates was performed or not
34863  bool unrefinement_was_performed=false;
34864 
34865  unsigned n_vertex = vector_bnd_vertices.size();
34866 
34867  // Initialise counter that indicates at which vertex we're currently
34868  // considering for deletion
34869  unsigned counter=1;
34870 
34871  // Loop over the nodes; start with the second one and increment by two
34872  // this way a "pack" of three nodes will be considered for calculation:
34873  // the middle-node (which is to be deleted or not) and the adjacent
34874  // nodes
34875  for(unsigned i=1;i<=n_vertex-2;i+=2)
34876  {
34877  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
34878  double a_x=vector_bnd_vertices[i-1][1];
34879  double a_y=vector_bnd_vertices[i-1][2];
34880  double b_x=vector_bnd_vertices[i][1];
34881  double b_y=vector_bnd_vertices[i][2];
34882  double c_x=vector_bnd_vertices[i+1][1];
34883  double c_y=vector_bnd_vertices[i+1][2];
34884 
34885  double a=b_x-a_x;
34886  double b=b_y-a_y;
34887  double c=c_x-a_x;
34888  double d=c_y-a_y;
34889 
34890  double e=a*(a_x+b_x)+b*(a_y+b_y);
34891  double f=c*(a_x+c_x)+d*(a_y+c_y);
34892 
34893  double g=2.0*(a*(c_y-b_y)-b*(c_x-b_x));
34894 
34895  bool do_it=false;
34896  if (std::fabs(g)<1.0e-14)
34897  {
34898  do_it=true;
34899  if(check_only) {return true;}
34900  }
34901  else
34902  {
34903  double p_x=(d*e-b*f)/g;
34904  double p_y=(a*f-c*e)/g;
34905 
34906  double r=sqrt(pow((a_x-p_x),2)+pow((a_y-p_y),2));
34907 
34908  double rhalfca_x=0.5*(a_x-c_x);
34909  double rhalfca_y=0.5*(a_y-c_y);
34910 
34911  double halfca_squared=pow(rhalfca_x,2)+pow(rhalfca_y,2);
34912 
34913  double sticky_out_bit=r-sqrt(std::fabs((r*r) - halfca_squared));
34914 
34915  // If sticky out bit divided by distance between end nodes
34916  // is less than tolerance the boundary is so flat that we
34917  // can safely kill the node
34918  if ((sticky_out_bit/(2.0*sqrt(halfca_squared)))<
34919  unrefinement_tolerance)
34920  {
34921  do_it=true;
34922  if(check_only) {return true;}
34923  }
34924  }
34925 
34926  // If the vertex was proposed for deletion check that it is
34927  // allowed for being deleted
34928  if (do_it && boundary_receive_connections)
34929  {
34930  // Is the vertex one of the non deletable vertices
34931  for (std::set<Vector<double> >::iterator it = no_delete_vertex.begin();
34932  it != no_delete_vertex.end(); it++)
34933  {
34934  // Compute the distance between the proposed node to delete
34935  // and the ones that should not be deleted
34936  const double x = (*it)[0];
34937  const double y = (*it)[1];
34938  double error = (b_x - x)*(b_x - x) + (b_y - y)*(b_y - y);
34939  error = sqrt(error);
34940 
34942  {
34943  // Do not delete the vertex
34944  do_it = false;
34945  break;
34946  }
34947 
34948  }
34949 
34950  } // if (do_it && boundary_receive_connections)
34951 
34952  // Remove node?
34953  if (do_it)
34954  {
34955  vector_bnd_vertices[i].resize(0);
34956  }
34957 
34958  // Increase the counter, that indicates the number of the
34959  // next middle node
34960  counter+=2;
34961  }
34962 
34963  // coming out of here the value of counter is the index of the
34964  // last node on the polyline counter=n_vertex-1 (in case of an
34965  // even number of nodes) or counter has the value of the number
34966  // of nodes on the polyline counter=n_vertex (in case of an odd
34967  // number of nodes
34968 
34969  // Special treatment for the end of the polyline:
34970  // If the number of nodes is even, then the previous loop stopped
34971  // at the last but second node, i.e. the current value of counter
34972  // is the index of the last node. If that's the case, the last but
34973  // one node needs to be treated separately
34974  if( (counter)==(n_vertex-1) )
34975  {
34976  // Set the last but one node as middle node
34977  unsigned i=vector_bnd_vertices.size()-2;
34978 
34979  // Index of the current! last but second node (considering any
34980  // previous deletion)
34981  unsigned n=0;
34982 
34983  if(vector_bnd_vertices[counter-2].size()!=0)
34984  {
34985  // if the initial last but second node does still exist then
34986  // this one is obviously also the current last but second one
34987  n=counter-2;
34988  }
34989  else
34990  {
34991  // if the initial last but second node was deleted then the
34992  // initial last but third node is the current last but second
34993  // node
34994  n=counter-3;
34995  }
34996 
34997  // CODE DUPLICATION -- CAN'T BE BOTHERED TO WRITE A SEPARATE
34998  // FUNCTION FOR THIS; PROBABLY WORTH DOING IF/WHEN THERE'S
34999  // A MISTAKE IN ANY OF THIS AND IT NEEDS TO BE FIXED...
35000 
35001  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
35002  double a_x=vector_bnd_vertices[n][1];
35003  double a_y=vector_bnd_vertices[n][2];
35004  double b_x=vector_bnd_vertices[i][1];
35005  double b_y=vector_bnd_vertices[i][2];
35006  double c_x=vector_bnd_vertices[i+1][1];
35007  double c_y=vector_bnd_vertices[i+1][2];
35008 
35009  double a=b_x-a_x;
35010  double b=b_y-a_y;
35011  double c=c_x-a_x;
35012  double d=c_y-a_y;
35013 
35014  double e=a*(a_x+b_x)+b*(a_y+b_y);
35015  double f=c*(a_x+c_x)+d*(a_y+c_y);
35016 
35017  double g=2.0*(a*(c_y-b_y)-b*(c_x-b_x));
35018 
35019  bool do_it=false;
35020  if (std::fabs(g)<1.0e-14)
35021  {
35022  do_it=true;
35023  if(check_only) {return true;}
35024  }
35025  else
35026  {
35027  double p_x=(d*e-b*f)/g;
35028  double p_y=(a*f-c*e)/g;
35029 
35030  double r=sqrt(pow((a_x-p_x),2)+pow((a_y-p_y),2));
35031 
35032  double rhalfca_x=0.5*(a_x-c_x);
35033  double rhalfca_y=0.5*(a_y-c_y);
35034 
35035  double halfca_squared=pow(rhalfca_x,2)+pow(rhalfca_y,2);
35036 
35037  double sticky_out_bit=r-sqrt(std::fabs((r*r) - halfca_squared));
35038 
35039  // If sticky out bit divided by distance between end nodes
35040  // is less than tolerance the boundary is so flat that we
35041  // can safely kill the node
35042  if ((sticky_out_bit/(2.0*sqrt(halfca_squared)))<
35043  unrefinement_tolerance)
35044  {
35045  do_it=true;
35046  if(check_only) {return true;}
35047  }
35048  }
35049 
35050  // If the vertex was proposed for deletion check that it is
35051  // allowed for being deleted
35052  if (do_it && boundary_receive_connections)
35053  {
35054  // Is the vertex one of the non deletable vertices
35055  for (std::set<Vector<double> >::iterator it = no_delete_vertex.begin();
35056  it != no_delete_vertex.end(); it++)
35057  {
35058  // Compute the distance between the proposed node to delete
35059  // and the ones that should not be deleted
35060  const double x = (*it)[0];
35061  const double y = (*it)[1];
35062  double error = (b_x - x)*(b_x - x) + (b_y - y)*(b_y - y);
35063  error = sqrt(error);
35064 
35065  if(error <
35067  {
35068  // Do not delete the vertex
35069  do_it = false;
35070  break;
35071  }
35072 
35073  }
35074 
35075  } // if (do_it && boundary_receive_connections)
35076 
35077  // Remove node?
35078  if (do_it)
35079  {
35080  vector_bnd_vertices[i].resize(0);
35081  }
35082  }
35083 
35084  // Create another vector, which will only contain entries of
35085  // nodes that still exist
35086  Vector<Vector<double> > compact_vector;
35087  compact_vector.reserve(n_vertex);
35088  for (unsigned i=0;i<n_vertex;i++)
35089  {
35090  // If the entry was not deleted include it in the new vector
35091  if (vector_bnd_vertices[i].size()!=0)
35092  {
35093  compact_vector.push_back(vector_bnd_vertices[i]);
35094  }
35095  }
35096 
35097  /// Get the size of the vector that now includes all remaining nodes
35098  n_vertex =compact_vector.size();
35099 
35100  // If the size of the vector containing the remaining nodes is
35101  // different from the size of the vector before the unrefinement
35102  // routine (with the original nodes)
35103  // then the polyline was obviously updated
35104  if( n_vertex != vector_bnd_vertices.size() )
35105  {
35106  unrefinement_was_performed=true;
35107  }
35108 
35109  /// Copy back
35110  vector_bnd_vertices.resize(n_vertex);
35111  for(unsigned i=0;i<n_vertex;i++)
35112  {
35113  vector_bnd_vertices[i].resize(3);
35114  vector_bnd_vertices[i][0]=compact_vector[i][0];
35115  vector_bnd_vertices[i][1]=compact_vector[i][1];
35116  vector_bnd_vertices[i][2]=compact_vector[i][2];
35117  }
35118 
35119  return unrefinement_was_performed;
35120 
35121  }
35122 
35123 //=========================================================================
35124 /// \short Helper function that performs the refinement process
35125 /// on the specified boundary by using the provided vertices
35126 /// representation. Optional boolean is used to run it as test only (if
35127 /// true is specified as input) in which case vertex coordinates aren't
35128 /// actually modified. Returned boolean indicates if polyline was (or
35129 /// would have been -- if called with check_only=false) changed.
35130 //=========================================================================
35131 template<class ELEMENT>
35133 refine_boundary(Mesh* face_mesh_pt,
35134  Vector<Vector<double> > &vector_bnd_vertices,
35135  double &refinement_tolerance,
35136  const bool &check_only)
35137  {
35138  // Boolean that indicates whether an actual update of the vertex
35139  // coordinates was performed or not
35140  bool refinement_was_performed=false;
35141 
35142  // Create a geometric object from the mesh to represent
35143  //the curvilinear boundary
35144  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt);
35145 
35146  // Get the total number of current vertices
35147  unsigned n_vertex=vector_bnd_vertices.size();
35148 
35149  // Create a new (temporary) vector for the nodes, so
35150  // that new nodes can be stored
35151  Vector<Vector<double> > extended_vector;
35152 
35153  // Reserve memory space for twice the number of already
35154  // existing nodes (worst case)
35155  extended_vector.reserve(2*n_vertex);
35156 
35157  // Loop over the nodes until the last but one node
35158  for(unsigned inod=0;inod<n_vertex-1;inod++)
35159  {
35160  // Get local coordinate of "left" node
35161  double zeta_left=vector_bnd_vertices[inod][0];
35162 
35163  // Get position vector of "left" node
35164  Vector<double> R_left(2);
35165  for(unsigned i=0;i<2;i++)
35166  {
35167  R_left[i]=vector_bnd_vertices[inod][i+1];
35168  }
35169 
35170  // Get local coordinate of "right" node
35171  double zeta_right=vector_bnd_vertices[inod+1][0];
35172 
35173  // Get position vector of "right" node
35174  Vector<double> R_right(2);
35175  for(unsigned i=0;i<2;i++)
35176  {
35177  R_right[i]=vector_bnd_vertices[inod+1][i+1];
35178  }
35179 
35180  // Get the boundary coordinate of the midpoint
35181  Vector<double> zeta_mid(1);
35182  zeta_mid[0]=0.5*(zeta_left+zeta_right);
35183 
35184  // Get the position vector of the midpoint on the
35185  // curvilinear boundary
35186  Vector<double> R_mid(2);
35187  mesh_geom_obj_pt->position(zeta_mid,R_mid);
35188 
35189  // Get the position vector of the midpoint on the straight
35190  // line connecting "left" and "right" node
35191  Vector<double> R_mid_polygon(2);
35192  for(unsigned i=0;i<2;i++)
35193  {
35194  R_mid_polygon[i]=0.5*(R_right[i]+R_left[i]);
35195  }
35196 
35197  // Calculate the distance between the midpoint on the curvilinear
35198  // boundary and the midpoint on the straight line
35199  double distance=sqrt((R_mid[0]-R_mid_polygon[0])*
35200  (R_mid[0]-R_mid_polygon[0])+
35201  (R_mid[1]-R_mid_polygon[1])*
35202  (R_mid[1]-R_mid_polygon[1]));
35203 
35204  // Calculating the length of the straight line
35205  double length=sqrt((R_right[0]-R_left[0])*(R_right[0]-R_left[0])+
35206  (R_right[1]-R_left[1])*(R_right[1]-R_left[1]));
35207 
35208  // If the ratio of distance between the midpoints to the length
35209  // of the straight line is larger than the tolerance
35210  // specified for the criterion when points can be deleted,
35211  // create a new node and add it to the (temporary) vector
35212  if((distance/length) > refinement_tolerance)
35213  {
35214 
35215  if(check_only)
35216  {
35217  // Delete the allocated memory for the geometric object
35218  // that represents the curvilinear boundary
35219  delete mesh_geom_obj_pt;
35220  return true;
35221  }
35222 
35223  Vector<double> new_node(3);
35224  new_node[0]=zeta_mid[0];
35225  new_node[1]=R_mid[0];
35226  new_node[2]=R_mid[1];
35227 
35228  // Include the "left" node in the new "temporary" vector
35229  extended_vector.push_back(vector_bnd_vertices[inod]);
35230 
35231  // Include the new node as well
35232  extended_vector.push_back(new_node);
35233 
35234  }
35235  else
35236  {
35237  // Include the "left" node in the new "temporary" vector
35238  // and move on to the next node
35239  extended_vector.push_back(vector_bnd_vertices[inod]);
35240  }
35241  } // end of loop over nodes
35242 
35243  // Add the last node to the vector
35244  extended_vector.push_back(vector_bnd_vertices[n_vertex-1]);
35245 
35246  /// Get the size of the vector that now includes all added nodes
35247  n_vertex=extended_vector.size();
35248 
35249  // If the size of the vector including the added nodes is
35250  // different from the size of the vector before the refinement
35251  // routine then the polyline was obviously updated
35252  if( n_vertex != vector_bnd_vertices.size() )
35253  {
35254  refinement_was_performed=true;
35255  }
35256 
35257  // Copy across
35258  vector_bnd_vertices.resize(n_vertex);
35259  for(unsigned i=0;i<n_vertex;i++)
35260  {
35261  vector_bnd_vertices[i].resize(3);
35262  vector_bnd_vertices[i][0]=extended_vector[i][0];
35263  vector_bnd_vertices[i][1]=extended_vector[i][1];
35264  vector_bnd_vertices[i][2]=extended_vector[i][2];
35265  }
35266 
35267  // Delete the allocated memory for the geometric object
35268  // that represents the curvilinear boundary
35269  delete mesh_geom_obj_pt;
35270 
35271  return refinement_was_performed;
35272 
35273  }
35274 
35275  //=========================================================================
35276  // \short Helper function that applies the maximum length constraint
35277  // when it was specified. This will increase the number of points in
35278  // the current curve section in case that any segment on it does not
35279  // fulfils the requirement
35280  //=========================================================================
35281  template<class ELEMENT>
35284  Vector<Vector<double> > &vector_bnd_vertices,
35285  double &max_length_constraint)
35286  {
35287  // Boolean that indicates whether an actual update of the vertex
35288  // coordinates was performed or not
35289  bool max_length_applied=false;
35290 
35291  // Create a geometric object from the mesh to represent
35292  //the curvilinear boundary
35293  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt);
35294 
35295  // Get the total number of current vertices
35296  unsigned n_vertex=vector_bnd_vertices.size();
35297 
35298  // Create a new (temporary) vector for the nodes, so
35299  // that new nodes can be stored
35300  Vector<Vector<double> > extended_vector;
35301 
35302  // Loop over the nodes until the last but one node
35303  for(unsigned inod=0;inod<n_vertex-1;inod++)
35304  {
35305  // Get local coordinate of "left" node
35306  double zeta_left=vector_bnd_vertices[inod][0];
35307 
35308  // Get position vector of "left" node
35309  Vector<double> R_left(2);
35310  for(unsigned i=0;i<2;i++)
35311  {
35312  R_left[i]=vector_bnd_vertices[inod][i+1];
35313  }
35314 
35315  // Get local coordinate of "right" node
35316  double zeta_right=vector_bnd_vertices[inod+1][0];
35317 
35318  // Get position vector of "right" node
35319  Vector<double> R_right(2);
35320  for(unsigned i=0;i<2;i++)
35321  {
35322  R_right[i]=vector_bnd_vertices[inod+1][i+1];
35323  }
35324 
35325  // Include the "left" node in the new "temporary" vector
35326  extended_vector.push_back(vector_bnd_vertices[inod]);
35327 
35328  // Check whether the current distance between the left and right node
35329  // is longer than the specified constraint or not
35330  double length=std::fabs(zeta_right-zeta_left);
35331 
35332  // Do we need to introduce new nodes?
35333  if (length > max_length_constraint)
35334  {
35335  double n_pts = length/max_length_constraint;
35336  // We only want the integer part
35337  unsigned n_points = static_cast<unsigned>(n_pts);
35338  double zeta_increment = (zeta_right-zeta_left)/((double)n_points+1);
35339 
35340  Vector<double> zeta(1);
35341  // Create the n_points+1 points inside the segment
35342  for(unsigned s=1;s<n_points+1;s++)
35343  {
35344  // Get the coordinates
35345  zeta[0]= zeta_left + zeta_increment*double(s);
35346  Vector<double> vertex(2);
35347  mesh_geom_obj_pt->position(zeta, vertex);
35348 
35349  // Create the new node
35350  Vector<double> new_node(3);
35351  new_node[0]=zeta[0];
35352  new_node[1]=vertex[0];
35353  new_node[2]=vertex[1];
35354 
35355  // Include the new node
35356  extended_vector.push_back(new_node);
35357  }
35358  }
35359  }
35360 
35361  // Add the last node to the vector
35362  extended_vector.push_back(vector_bnd_vertices[n_vertex-1]);
35363 
35364  /// Get the size of the vector that now includes all added nodes
35365  n_vertex=extended_vector.size();
35366 
35367  // If the size of the vector including the added nodes is
35368  // different from the size of the vector before applying the maximum length
35369  // constraint then the polyline was obviously updated
35370  if( n_vertex != vector_bnd_vertices.size() )
35371  {
35372  max_length_applied = true;
35373  }
35374 
35375  // Copy across
35376  vector_bnd_vertices.resize(n_vertex);
35377  for(unsigned i=0;i<n_vertex;i++)
35378  {
35379  vector_bnd_vertices[i].resize(3);
35380  vector_bnd_vertices[i][0]=extended_vector[i][0];
35381  vector_bnd_vertices[i][1]=extended_vector[i][1];
35382  vector_bnd_vertices[i][2]=extended_vector[i][2];
35383  }
35384 
35385  // Delete the allocated memory for the geometric object
35386  // that represents the curvilinear boundary
35387  delete mesh_geom_obj_pt;
35388 
35389  return max_length_applied;
35390 
35391  }
35392 
35393 //=========================================================================
35394 /// \short Helper function
35395 /// Creates an unsorted face mesh representation from the specified
35396 /// boundary id. It means that the elements are not sorted along the
35397 /// boundary
35398 //=========================================================================
35399 template<class ELEMENT>
35402  const unsigned &boundary_id,
35403  Mesh* face_mesh_pt)
35404  {
35405  // Create a face mesh adjacent to specified boundary.
35406  // The face mesh consists of FaceElements that may also be
35407  // interpreted as GeomObjects
35408 
35409  // Build the face mesh
35410  this->template build_face_mesh<ELEMENT,FaceElementAsGeomObject>
35411  (boundary_id,face_mesh_pt);
35412 
35413  // Find the total number of added elements
35414  unsigned n_element = face_mesh_pt->nelement();
35415  // Loop over the elements
35416  for(unsigned e=0;e<n_element;e++)
35417  {
35418 
35419  //Cast the element pointer to the correct thing!
35421  dynamic_cast<FaceElementAsGeomObject<ELEMENT>*>
35422  (face_mesh_pt->element_pt(e));
35423 
35424  // Set bulk boundary number
35425  el_pt->set_boundary_number_in_bulk_mesh(boundary_id);
35426 
35427  }
35428 
35429  }
35430 
35431 //=========================================================================
35432 /// \short Helper function
35433 /// Creates a sorted face mesh representation of the specified PolyLine
35434 /// It means that the elements are sorted along the boundary
35435 //=========================================================================
35436 template<class ELEMENT>
35439  const unsigned &boundary_id,
35440  Mesh* face_mesh_pt,
35441  std::map<FiniteElement*, bool> &is_inverted,
35442  bool &inverted_face_mesh)
35443  {
35444  Mesh *tmp_unsorted_face_mesh_pt = new Mesh();
35445 
35446  // First step we get the unsorted version of the face mesh
35447  create_unsorted_face_mesh_representation(
35448  boundary_id, tmp_unsorted_face_mesh_pt);
35449 
35450  // Once with the unsorted version of the face mesh
35451  // only left to sort it out!!!
35452 
35453  // Put all face elements in order
35454  //-------------------------------
35455 
35456  // Put first element into ordered list
35457  // Temporal list for sorting the elements
35458  std::list<FiniteElement*> sorted_el_pt;
35459  FiniteElement* el_pt = tmp_unsorted_face_mesh_pt->finite_element_pt(0);
35460  sorted_el_pt.push_back(el_pt);
35461 
35462  // Number of nodes
35463  unsigned nnod=el_pt->nnode();
35464 
35465  // Count elements that have been done
35466  unsigned count_done=0;
35467 
35468  // How many face elements are there?
35469  unsigned n_face_element = tmp_unsorted_face_mesh_pt->nelement();
35470 
35471  // Keep track of who's done
35472  std::map<FiniteElement*,bool> done_el;
35473 
35474  is_inverted.clear();
35475 
35476  // Fit in the other elements in at most nel^2 loops
35477  for (unsigned ee=1;ee<n_face_element;ee++)
35478  {
35479  // Loop over all elements to check if they fit to the right
35480  // or the left of the current one
35481  for (unsigned e=1;e<n_face_element;e++)
35482  {
35483  // Candidate element
35484  el_pt=tmp_unsorted_face_mesh_pt->finite_element_pt(e);
35485 
35486  // Is it done yet?
35487  if (!done_el[el_pt])
35488  {
35489  // Left and rightmost elements
35490  FiniteElement* first_el_pt=(*sorted_el_pt.begin());
35491  std::list<FiniteElement*>::iterator it=sorted_el_pt.end();
35492  it--;
35493  FiniteElement* last_el_pt=*it;
35494 
35495  // Left and rightmost nodes
35496  Node* left_node_pt=first_el_pt->node_pt(0);
35497  if (is_inverted[first_el_pt])
35498  {
35499  left_node_pt=first_el_pt->node_pt(nnod-1);
35500  }
35501  Node* right_node_pt=last_el_pt->node_pt(nnod-1);
35502  if (is_inverted[last_el_pt])
35503  {
35504  right_node_pt=last_el_pt->node_pt(0);
35505  }
35506 
35507  // New element fits at the left of first element and is not inverted
35508  if (left_node_pt==el_pt->node_pt(nnod-1))
35509  {
35510  sorted_el_pt.push_front(el_pt);
35511  done_el[el_pt]=true;
35512  count_done++;
35513  is_inverted[el_pt]=false;
35514  }
35515  // New element fits at the left of first element and is inverted
35516 
35517  else if (left_node_pt==el_pt->node_pt(0))
35518  {
35519  sorted_el_pt.push_front(el_pt);
35520  done_el[el_pt]=true;
35521  count_done++;
35522  is_inverted[el_pt]=true;
35523  }
35524  // New element fits on the right of last element and is not inverted
35525 
35526  else if(right_node_pt==el_pt->node_pt(0))
35527  {
35528  sorted_el_pt.push_back(el_pt);
35529  done_el[el_pt]=true;
35530  count_done++;
35531  is_inverted[el_pt]=false;
35532  }
35533  // New element fits on the right of last element and is inverted
35534 
35535  else if (right_node_pt==el_pt->node_pt(nnod-1))
35536  {
35537  sorted_el_pt.push_back(el_pt);
35538  done_el[el_pt]=true;
35539  count_done++;
35540  is_inverted[el_pt]=true;
35541  }
35542 
35543  if (done_el[el_pt])
35544  {
35545  break;
35546  }
35547  }
35548  }
35549  }
35550 
35551  // Are we done?
35552  if (count_done!=(n_face_element-1))
35553  {
35554  std::ostringstream error_message;
35555  error_message
35556  << "When ordering FaceElements on "
35557  << "boundary " << boundary_id << " only managed to order \n" << count_done
35558  << " of " << n_face_element << " face elements.\n"
35559  << std::endl;
35560  throw OomphLibError(
35561  error_message.str(),
35562  OOMPH_CURRENT_FUNCTION,
35563  OOMPH_EXCEPTION_LOCATION);
35564  }
35565 
35566  // Now make a mesh that contains the FaceElements in order
35567  // Remember that we currently have a list, not a mesh of sorted elements
35568 
35569  // Fill it
35570  for (std::list<FiniteElement*>::iterator it=sorted_el_pt.begin();
35571  it!=sorted_el_pt.end();it++)
35572  {
35573  // Get element
35574  FiniteElement* el_pt=*it;
35575 
35576  // add this face element to the order original mesh
35577  face_mesh_pt->add_element_pt(el_pt);
35578  }
35579 
35580  // Verify if face mesh representation is not inverted according to the
35581  // polyline specified by the user, it means that the initial and the
35582  // final vertex does really correspond to the first and last vertex
35583  // respectively, if not, state that the face mesh representation is
35584  // inverted
35585 
35586  // Get the associated polyline representation to the boundary
35587  TriangleMeshPolyLine *bnd_polyline =
35588  this->Boundary_curve_section_pt[boundary_id];
35589 
35590  // Get the really first vertex
35591  Vector<double> first_vertex =
35592  bnd_polyline->vertex_coordinate(0);
35593 
35594  // Now get the first node based on the face mesh representation
35595  // First get access to the first element
35596  FiniteElement* first_el_pt =
35597  face_mesh_pt->finite_element_pt(0);
35598 
35599  // Now get access to the first node
35600  unsigned n_node = first_el_pt->nnode();
35601  // Get the very first node (taking into account if it is
35602  // inverted or not!!)
35603  Node* first_node_pt = first_el_pt->node_pt(0);
35604  if (is_inverted[first_el_pt])
35605  {
35606  first_node_pt = first_el_pt->node_pt(n_node-1);
35607  }
35608 
35609  double error = (first_node_pt->x(0) - first_vertex[0])*
35610  (first_node_pt->x(0) - first_vertex[0]) +
35611  (first_node_pt->x(1) - first_vertex[1])*
35612  (first_node_pt->x(1) - first_vertex[1]);
35613 
35614  error = sqrt(error);
35615 
35616  if(error <
35618  {
35619  inverted_face_mesh = false;
35620  }
35621  else
35622  {
35623  inverted_face_mesh = true;
35624  }
35625 
35626  }
35627 
35628 //=========================================================================
35629 /// Helper function to construct face mesh representation of all polylines,
35630 /// possibly with segments re-distributed between polylines
35631 /// to maintain an approximately even sub-division of the polygon
35632 //=========================================================================
35633 template<class ELEMENT>
35636  Vector<Mesh*>& face_mesh_pt)
35637  {
35638  // Number of polylines
35639  unsigned n_polyline = polygon_pt->npolyline();
35640  face_mesh_pt.resize(n_polyline);
35641 
35642  // Are we eligible for re-distributing polyline segments between
35643  // polylines? We're not if any of the boundaries are associated
35644  // with a GeomObject because we're then tied to the start and
35645  // end coordinates along it.
35646  bool eligible_for_segment_redistribution=true;
35647 
35648  // Loop over constituent polylines
35649  for(unsigned p=0;p<n_polyline;p++)
35650  {
35651 
35652  //Get the boundary id of the polyline
35653  unsigned bound =
35654  polygon_pt->polyline_pt(p)->boundary_id();
35655 
35656  //If the boundary has a geometric object representation then
35657  //we can't redistribute
35658  GeomObject* const geom_object_pt =
35659  this->boundary_geom_object_pt(bound);
35660  if(geom_object_pt!=0)
35661  {
35662  eligible_for_segment_redistribution=false;
35663  }
35664 
35665  face_mesh_pt[p] = new Mesh();
35666  create_unsorted_face_mesh_representation(
35667  bound, face_mesh_pt[p]);
35668 
35669  }
35670 
35672  {
35673  return;
35674  }
35675 
35676  //If there is more than one region we have to think... Die for now.
35677  if(this->nregion() > 1)
35678  {
35679  std::ostringstream warn_message;
35680  warn_message
35681  << "Can't currently re-distribute segments between polylines if there\n"
35682  << "are multiple regions; returning..." << std::endl;
35683  OomphLibWarning(warn_message.str(),
35684  "RefineableTriangleMesh::get_face_mesh_representation()",
35685  OOMPH_EXCEPTION_LOCATION);
35686  return;
35687  }
35688 
35689  // Redistribution overruled
35690  if (!eligible_for_segment_redistribution)
35691  {
35692  std::ostringstream warn_message;
35693  warn_message
35694  << "Over-ruling re-distribution of segments between polylines\n"
35695  << "because at least one boundary is associated with a GeomObject."
35696  << "Returning..." << std::endl;
35697  OomphLibWarning(warn_message.str(),
35698  "RefineableTriangleMesh::get_face_mesh_representation()",
35699  OOMPH_EXCEPTION_LOCATION);
35700  return;
35701  }
35702 
35703  // Create a vector for ordered face mesh
35704  Vector<Mesh*> ordered_face_mesh_pt(n_polyline);
35705 
35706  // Storage for the total arclength of polygon
35707  double s_total=0.0;
35708 
35709  // Storage for first and last nodes on polylines so we can figure
35710  // out if they are inverted relative to each other
35711  Vector<Node*> first_polyline_node_pt(n_polyline);
35712  Vector<Node*> last_polyline_node_pt(n_polyline);
35713  std::vector<bool> is_reversed(n_polyline,false);
35714 
35715  // Loop over constituent polylines
35716  for(unsigned p=0;p<n_polyline;p++)
35717  {
35718 
35719  // Put all face elements in order
35720  //-------------------------------
35721 
35722  // Put first element into ordered list
35723  std::list<FiniteElement*> ordered_el_pt;
35724  FiniteElement* el_pt=face_mesh_pt[p]->finite_element_pt(0);
35725  ordered_el_pt.push_back(el_pt);
35726 
35727  // Number of nodes
35728  unsigned nnod=el_pt->nnode();
35729 
35730  // Default for first and last node on polyline
35731  first_polyline_node_pt[p]=el_pt->node_pt(0);
35732  last_polyline_node_pt[p]=el_pt->node_pt(nnod-1);
35733 
35734  // Count elements that have been done
35735  unsigned count_done=0;
35736 
35737  // How many face elements are there?
35738  unsigned n_face_element = face_mesh_pt[p]->nelement();
35739 
35740  //Get the boundary id of the polyline
35741  unsigned bound =
35742  polygon_pt->polyline_pt(p)->boundary_id();
35743 
35744  // Keep track of who's done
35745  std::map<FiniteElement*,bool> done_el;
35746 
35747  // Keep track of which element is inverted
35748  std::map<FiniteElement*,bool> is_inverted;
35749 
35750  // Fit in the other elements in at most nel^2 loops
35751  for (unsigned ee=1;ee<n_face_element;ee++)
35752  {
35753  // Loop over all elements to check if they fit to the right
35754  // or the left of the current one
35755  for (unsigned e=1;e<n_face_element;e++)
35756  {
35757  // Candidate element
35758  el_pt=face_mesh_pt[p]->finite_element_pt(e);
35759 
35760  // Is it done yet?
35761  if (!done_el[el_pt])
35762  {
35763  // Left and rightmost elements
35764  FiniteElement* first_el_pt=(*ordered_el_pt.begin());
35765  std::list<FiniteElement*>::iterator it=ordered_el_pt.end();
35766  it--;
35767  FiniteElement* last_el_pt=*it;
35768 
35769  // Left and rightmost nodes
35770  Node* left_node_pt=first_el_pt->node_pt(0);
35771  if (is_inverted[first_el_pt])
35772  {
35773  left_node_pt=first_el_pt->node_pt(nnod-1);
35774  }
35775  Node* right_node_pt=last_el_pt->node_pt(nnod-1);
35776  if (is_inverted[last_el_pt])
35777  {
35778  right_node_pt=last_el_pt->node_pt(0);
35779  }
35780 
35781  // New element fits at the left of first element and is not inverted
35782  if (left_node_pt==el_pt->node_pt(nnod-1))
35783  {
35784  ordered_el_pt.push_front(el_pt);
35785  done_el[el_pt]=true;
35786  count_done++;
35787  is_inverted[el_pt]=false;
35788  first_polyline_node_pt[p]=el_pt->node_pt(0);
35789  }
35790  // New element fits at the left of first element and is inverted
35791 
35792  else if (left_node_pt==el_pt->node_pt(0))
35793  {
35794  ordered_el_pt.push_front(el_pt);
35795  done_el[el_pt]=true;
35796  count_done++;
35797  is_inverted[el_pt]=true;
35798  first_polyline_node_pt[p]=el_pt->node_pt(nnod-1);
35799  }
35800  // New element fits on the right of last element and is not inverted
35801 
35802  else if(right_node_pt==el_pt->node_pt(0))
35803  {
35804  ordered_el_pt.push_back(el_pt);
35805  done_el[el_pt]=true;
35806  count_done++;
35807  is_inverted[el_pt]=false;
35808  last_polyline_node_pt[p]=el_pt->node_pt(nnod-1);
35809  }
35810  // New element fits on the right of last element and is inverted
35811 
35812  else if (right_node_pt==el_pt->node_pt(nnod-1))
35813  {
35814  ordered_el_pt.push_back(el_pt);
35815  done_el[el_pt]=true;
35816  count_done++;
35817  is_inverted[el_pt]=true;
35818  last_polyline_node_pt[p]=el_pt->node_pt(0);
35819  }
35820 
35821  if (done_el[el_pt])
35822  {
35823  break;
35824  }
35825  }
35826  }
35827  }
35828 
35829  // Are we done?
35830  if (count_done!=(n_face_element-1))
35831  {
35832  std::ostringstream error_message;
35833  error_message
35834  << "When ordering FaceElements on "
35835  << "boundary " << bound << " only managed to order \n" << count_done
35836  << " of " << n_face_element << " face elements.\n"
35837  << std::endl;
35838  throw OomphLibError(
35839  error_message.str(),
35840  OOMPH_CURRENT_FUNCTION,
35841  OOMPH_EXCEPTION_LOCATION);
35842  }
35843 
35844  // Now make a mesh that contains the FaceElements in order
35845  ordered_face_mesh_pt[p] = new Mesh;
35846 
35847  // Fill it
35848  for (std::list<FiniteElement*>::iterator it=ordered_el_pt.begin();
35849  it!=ordered_el_pt.end();it++)
35850  {
35851  // Get element
35852  FiniteElement* el_pt=*it;
35853 
35854  // add this face element to the order original mesh
35855  ordered_face_mesh_pt[p]->add_element_pt(el_pt);
35856  }
35857 
35858  //Get the arclength along the polygon
35859  for(unsigned e=0;e<n_face_element;++e)
35860  {
35861  FiniteElement* el_pt=ordered_face_mesh_pt[p]->finite_element_pt(e);
35862  unsigned n_node=el_pt->nnode();
35863  double element_length_squared=0.0;
35864  for(unsigned i=0;i<2;i++)
35865  {
35866  element_length_squared += pow(el_pt->node_pt(n_node-1)->x(i)-
35867  el_pt->node_pt(0)->x(i),2);
35868  }
35869 
35870  // Determine element length
35871  double element_length=sqrt(element_length_squared);
35872 
35873  // Add this length to the total arclength
35874  s_total += element_length;
35875  }
35876 
35877  // Empty the original meshes
35878  face_mesh_pt[p]->flush_element_and_node_storage();
35879  }
35880 
35881  // Is first one reversed?
35882  if ((last_polyline_node_pt[0]==first_polyline_node_pt[1])||
35883  (last_polyline_node_pt[0]==last_polyline_node_pt[1]))
35884  {
35885  is_reversed[0]=false;
35886  }
35887  else if ((first_polyline_node_pt[0]==first_polyline_node_pt[1])||
35888  (first_polyline_node_pt[0]==last_polyline_node_pt[1]))
35889  {
35890  is_reversed[0]=true;
35891  }
35892 
35893  // Reorder the face meshes so that they are contiguous
35894  Vector<Mesh*> tmp_face_mesh_pt(n_polyline);
35895  std::vector<bool> mesh_done(n_polyline,false);
35896  Vector<unsigned> old_polyline_number(n_polyline);
35897 
35898  // Initial entry
35899  tmp_face_mesh_pt[0]=ordered_face_mesh_pt[0];
35900  unsigned current=0;
35901  old_polyline_number[0]=0;
35902  unsigned count_found=0;
35903 
35904  // Fill in the next entries
35905  for(unsigned p=1;p<n_polyline;p++)
35906  {
35907  Node* end_node_pt=last_polyline_node_pt[current];
35908  if (is_reversed[current])
35909  {
35910  end_node_pt=first_polyline_node_pt[current];
35911  }
35912 
35913  // Loop over all remaining face meshes to see which one fits
35914  for(unsigned pp=1;pp<n_polyline;pp++)
35915  {
35916  if (!mesh_done[pp])
35917  {
35918  // Current one is not reversed, candidate is not reversed
35919  if ((!is_reversed[current])&&
35920  (end_node_pt==first_polyline_node_pt[pp]))
35921  {
35922  tmp_face_mesh_pt[p]=ordered_face_mesh_pt[pp];
35923  mesh_done[pp]=true;
35924  is_reversed[pp]=false;
35925  old_polyline_number[p]=pp;
35926  current=pp;
35927  count_found++;
35928  break;
35929  }
35930  // Current one is not reversed, candidate is reversed
35931 
35932  else if ((!is_reversed[current])&&
35933  (end_node_pt==last_polyline_node_pt[pp]))
35934  {
35935  tmp_face_mesh_pt[p]=ordered_face_mesh_pt[pp];
35936  mesh_done[pp]=true;
35937  is_reversed[pp]=true;
35938  old_polyline_number[p]=pp;
35939  current=pp;
35940  count_found++;
35941  break;
35942  }
35943  // Current one is reversed, candidate is not reversed
35944 
35945  else if ((is_reversed[current])&&
35946  (end_node_pt==first_polyline_node_pt[pp]))
35947  {
35948  tmp_face_mesh_pt[p]=ordered_face_mesh_pt[pp];
35949  mesh_done[pp]=true;
35950  is_reversed[pp]=false;
35951  old_polyline_number[p]=pp;
35952  current=pp;
35953  count_found++;
35954  break;
35955  }
35956  // Current one is reversed, candidate is reversed
35957 
35958  else if ((is_reversed[current])&&
35959  (end_node_pt==last_polyline_node_pt[pp]))
35960  {
35961  tmp_face_mesh_pt[p]=ordered_face_mesh_pt[pp];
35962  mesh_done[pp]=true;
35963  is_reversed[pp]=true;
35964  old_polyline_number[p]=pp;
35965  current=pp;
35966  count_found++;
35967  break;
35968  }
35969  }
35970  }
35971  }
35972 
35973 #ifdef PARANOID
35974  if (count_found!=n_polyline-1)
35975  {
35976  std::ostringstream error_message;
35977  error_message << "Only found " << count_found
35978  << " out of " << n_polyline-1
35979  << " polylines to be fitted in.\n";
35980  throw OomphLibError(
35981  error_message.str(),
35982  OOMPH_CURRENT_FUNCTION,
35983  OOMPH_EXCEPTION_LOCATION);
35984  }
35985 #endif
35986 
35987  // Now overwrite the re-ordered data
35988  for (unsigned i=0;i<n_polyline;i++)
35989  {
35990  ordered_face_mesh_pt[i]=tmp_face_mesh_pt[i];
35991  }
35992 
35993  // Now do an approximate equidistribution of polylines
35994  //----------------------------------------------------
35995  double s=0.0;
35996  unsigned new_face_id=0;
35997 
35998  // Matrix map to indicate if node must not be removed from specified
35999  // boundary (!=0) or not (=0). Initialises itself to zero
36000  std::map<Node*,std::map<unsigned,unsigned> >
36001  node_must_not_be_removed_from_boundary_flag;
36002 
36003  // Loop over the old face mesh
36004  for(unsigned p=0;p<n_polyline;p++)
36005  {
36006  // Loop over the face elements
36007  unsigned n_face_element = ordered_face_mesh_pt[p]->nelement();
36008  for (unsigned e=0;e<n_face_element;e++)
36009  {
36010  unsigned el_number=e;
36011  if (is_reversed[p])
36012  {
36013  el_number=n_face_element-e-1;
36014  }
36015 
36016  FiniteElement* el_pt=
36017  ordered_face_mesh_pt[p]->finite_element_pt(el_number);
36018  unsigned n_node = el_pt->nnode();
36019 
36020  // Determine element length
36021  double element_length_squared=0.0;
36022  for(unsigned i=0;i<2;i++)
36023  {
36024  element_length_squared += pow(el_pt->node_pt(n_node-1)->x(i)-
36025  el_pt->node_pt(0)->x(i),2);
36026  }
36027  double element_length=sqrt(element_length_squared);
36028 
36029  // Add this length to the total arclength
36030  s += element_length;
36031 
36032  // Check if the current 'arclength' is less than the
36033  // whole 'arclength' divided by the number of polylines
36034  if(s < s_total/double(n_polyline)+1e-6)
36035  {
36036  // If so add this face element to the new face mesh
36037  face_mesh_pt[new_face_id]->add_element_pt(el_pt);
36038 
36039  unsigned bound_old =
36040  polygon_pt->polyline_pt(old_polyline_number[p])->boundary_id();
36041 
36042  unsigned bound_new =
36043  polygon_pt->polyline_pt(new_face_id)->boundary_id();
36044 
36045  // Loop over the nodes in the element
36046  for(unsigned i=0;i<n_node;i++)
36047  {
36048  // Get the pointer to the node
36049  Node* nod_pt=el_pt->node_pt(i);
36050 
36051  // If the two boundary id's are different, the face element's nodes
36052  // have to be added to the new boundary
36053  if(bound_new != bound_old)
36054  {
36055  // Add it to the new boundary
36056  add_boundary_node(bound_new,nod_pt);
36057 
36058  // We are happy for this node to be removed from the
36059  // old boundary?
36060  node_must_not_be_removed_from_boundary_flag[nod_pt][bound_old]+=0;
36061  }
36062 
36063  // If the face element hasn't moved, its nodes MUST remain
36064  // on that boundary (incl. any nodes that ar shared by
36065  // FaceElements that have moved (see above)
36066 
36067  else
36068  {
36069  node_must_not_be_removed_from_boundary_flag[nod_pt][bound_old]+=1;
36070  }
36071  }
36072  }
36073 
36074  // If not, reset the current 'arclength' to zero,
36075  // increase the new face id by one and go one element
36076  // back by decreasing e by one to make sure the current
36077  // element gets added to the next face mesh
36078 
36079  else
36080  {
36081  if(new_face_id!=n_polyline-1)
36082  {
36083  s=0.0;
36084  new_face_id++;
36085  --e;
36086  }
36087  else
36088  {
36089  s=0.0;
36090  --e;
36091  }
36092  }
36093  }
36094  } // end of loop over all polylines -- they are now re-distributed
36095 
36096 
36097  // Loop over all nodes on the boundaries of the polygon to remove
36098  // nodes from boundaries they are no longer on
36099  unsigned move_count=0;
36100  for (std::map<Node*,std::map<unsigned,unsigned> >::iterator
36101  it=node_must_not_be_removed_from_boundary_flag.begin();
36102  it!=node_must_not_be_removed_from_boundary_flag.end();it++)
36103  {
36104  // Get the node
36105  Node* nod_pt=(*it).first;
36106 
36107  // Now we loop over the boundaries that this node is on
36108  for (std::map<unsigned,unsigned>::iterator
36109  it_2=(*it).second.begin();it_2!=(*it).second.end();it_2++)
36110  {
36111  // Get the boundary id
36112  unsigned bound=(*it_2).first;
36113 
36114  // Remove it from that boundary?
36115  if((*it_2).second==0)
36116  {
36117  remove_boundary_node(bound,nod_pt);
36118  move_count++;
36119  }
36120  }
36121  }
36122 
36123  // Loop over the new face mesh to assign new boundary IDs
36124  for(unsigned p=0;p<n_polyline;p++)
36125  {
36126  //Get the boundary id of the polyline
36127  unsigned bound =
36128  polygon_pt->polyline_pt(p)->boundary_id();
36129 
36130  // Loop over the face elements
36131  unsigned n_face_element = face_mesh_pt[p]->nelement();
36132  for(unsigned e=0;e<n_face_element;e++)
36133  {
36134  //Cast the element pointer to the correct thing!
36136  dynamic_cast<FaceElementAsGeomObject<ELEMENT>*>
36137  (face_mesh_pt[p]->element_pt(e));
36138 
36139  // Set bulk boundary number
36140  el_pt->set_boundary_number_in_bulk_mesh(bound);
36141  }
36142  }
36143 
36144  // Update look-up for elements next to boundary
36145  setup_boundary_element_info();
36146 
36147  // Now re-create the boundary coordinates
36148  for(unsigned p=0;p<n_polyline;p++)
36149  {
36150  //Get the boundary id of the polyline
36151  unsigned bound =
36152  polygon_pt->polyline_pt(p)->boundary_id();
36153 
36154  // Do it
36155  this->template setup_boundary_coordinates<ELEMENT>(bound);
36156  }
36157 
36158  // Clean up
36159  for(unsigned p=0;p<n_polyline;p++)
36160  {
36161  // Flush the nodes from the face mesh to make sure we
36162  // don't delete them (the face mesh that we're returning from here
36163  // still needs them!)
36164  ordered_face_mesh_pt[p]->flush_element_and_node_storage();
36165  delete ordered_face_mesh_pt[p];
36166  }
36167 
36168  }
36169 
36170 //=========================================================================
36171 /// Helper function to construct face mesh representation of all polylines
36172 //=========================================================================
36173 template<class ELEMENT>
36176  TriangleMeshOpenCurve* open_polyline_pt,
36177  Vector<Mesh*>& face_mesh_pt)
36178 {
36179  // Number of polylines
36180  unsigned n_polyline = open_polyline_pt->ncurve_section();
36181  face_mesh_pt.resize(n_polyline);
36182 
36183  // Loop over constituent polylines
36184  for(unsigned p=0;p<n_polyline;p++)
36185  {
36186 
36187  //Get the boundary id of the polyline
36188  unsigned bound =
36189  open_polyline_pt->curve_section_pt(p)->boundary_id();
36190 
36191  face_mesh_pt[p] = new Mesh();
36192  create_unsorted_face_mesh_representation(
36193  bound, face_mesh_pt[p]);
36194 
36195  }
36196 
36197 }
36198 
36199 //======================================================================
36200 /// Update the PSLG that define the inner boundaries of the mesh.
36201 ///Optional boolean is used to run it as test only (if
36202 /// true is specified as input) in which case PSLG isn't actually
36203 /// modified. Returned boolean indicates if PSLG was (or would have
36204 /// been -- if called with check_only=false) changed.
36205 //======================================================================
36206 template <class ELEMENT>
36209  &internal_point_coord,
36210  const bool& check_only)
36211  {
36212  //Boolean to indicate whether an actual update of the internal
36213  // holes was performed
36214  bool update_was_performed=false;
36215  //Loop over the number of internal boundaries
36216  unsigned n_hole = internal_point_coord.size();
36217  for(unsigned ihole=0;ihole<n_hole;ihole++)
36218  {
36219  //Cache the pointer to the polygon representation
36220  TriangleMeshPolygon* const poly_pt
36221  = this->Internal_polygon_pt[ihole];
36222 
36223 
36224  //Can the polygon update its own configuration, in which case this
36225  //is easy
36226  if(poly_pt->can_update_reference_configuration())
36227  {
36228  poly_pt->reset_reference_configuration();
36229 
36230  // Initialize Vector hole_coordinates
36231  internal_point_coord[ihole].resize(2);
36232 
36233  // Get the vector of hole coordinates
36234  internal_point_coord[ihole]=poly_pt->internal_point();
36235  }
36236  //Otherwise we have to work much harder
36237 
36238  else
36239  {
36240  //if we only want to check whether an update of the inner
36241  //hole is necessary
36242  if(check_only)
36243  {
36244  //is it necessary?
36245  bool update_necessary=
36246  this->update_polygon_using_face_mesh(poly_pt,check_only);
36247 
36248  //Yes?
36249  if(update_necessary)
36250  {
36251  //then we have to adaptand return 'true'
36252  return true;
36253  }
36254  }
36255  //if we not only want to check, then we actually perform
36256  //the update
36257  else
36258  {
36259  update_was_performed=
36260  this->update_polygon_using_face_mesh(poly_pt);
36261  }
36262 
36263  //Now we need to sort out the hole coordinates
36264  if (!poly_pt->internal_point().empty())
36265  {
36266  //If fixed don't update and simply
36267  //Read out the existing value
36268  if(poly_pt->is_internal_point_fixed())
36269  {
36270  // Get the vector of hole coordinates
36271  internal_point_coord[ihole]=poly_pt->internal_point();
36272  }
36273  //This is where the work starts and this could be made much
36274  //better than the current hack
36275  else
36276  {
36277  //If the user has set their own function then use that
36278  if(this->Internal_hole_point_update_fct_pt!=0)
36279  {
36280  this->Internal_hole_point_update_fct_pt(ihole,poly_pt);
36281  }
36282  //Otherwise use our clunky default
36283  else
36284  {
36285  //Now sort out the hole coordinates
36286  Vector<double> vertex_coord;
36287  unsigned n_polyline = poly_pt->npolyline();
36288 
36289  // Initialize Vector hole_coordinates
36290  vertex_coord.resize(2);
36291  internal_point_coord[ihole].resize(2);
36292 
36293  //Hole centre will be found by averaging the position of
36294  //all vertex nodes
36295  internal_point_coord[ihole][0] = 0.0;
36296  internal_point_coord[ihole][1] = 0.0;
36297 
36298  for(unsigned p=0;p<n_polyline;p++)
36299  {
36300  Vector<double> poly_ave(2,0.0);
36301  //How many vertices are there in the segment
36302  unsigned n_vertex = poly_pt->polyline_pt(p)->nvertex();
36303  for(unsigned v=0;v<n_vertex;v++)
36304  {
36305  vertex_coord = poly_pt->polyline_pt(p)->vertex_coordinate(v);
36306  for(unsigned i=0;i<2;i++)
36307  {
36308  poly_ave[i] += vertex_coord[i];
36309  }
36310  }
36311 
36312  //Add the average polyline coordinate to the hole centre
36313  for(unsigned i=0;i<2;i++)
36314  {
36315  internal_point_coord[ihole][i] += poly_ave[i]/n_vertex;
36316  }
36317  }
36318 
36319  //Now average out the hole centre
36320  for(unsigned i=0;i<2;i++)
36321  {
36322  internal_point_coord[ihole][i] /= n_polyline;
36323  }
36324 
36325  //We have now found the hole centre stored in internal_point_coordinate[ihole][i]
36326 
36327  //Find polylines that intersect at y average value
36328  //Alice's version but this does not work if the end point of a
36329  //segment is the intersection point (i.e. at the y average value)
36330  /*Vector<double> vertex_coord2;
36331  unsigned n_intersect=0;
36332  double x_average=0.0;
36333 
36334  for(unsigned p=0;p<n_polyline;p++)
36335  {
36336  //How many vertices are there in the segment
36337  unsigned n_vertex = poly_pt->polyline_pt(p)->nvertex();
36338  for(unsigned v=0;v<n_vertex-1;v++)
36339  {
36340  vertex_coord = poly_pt->polyline_pt(p)->vertex_coordinate(v);
36341  vertex_coord2 = poly_pt->polyline_pt(p)->vertex_coordinate(v+1);
36342  std::cout << vertex_coord[0] << " " << vertex_coord[1]
36343  << " " <<
36344  vertex_coord2[0] << " " <<
36345 
36346  vertex_coord2[1] << "\n";
36347  //Does the line between vertices intersect the vertical position
36348  if((vertex_coord[1] -internal_point_coord[ihole][1])*
36349  (vertex_coord2[1] - internal_point_coord[ihole][1]) < 0.0)
36350  {
36351  ++n_intersect; x_average += 0.5*(vertex_coord[0] + vertex_coord2[0]);
36352  }
36353  }
36354  }
36355 
36356  //Now just report the value if we have had intersections
36357  if(n_intersect != 0)
36358  {
36359  //Report
36360  std::cout << "I have computed a hole " << x_average << " " << n_intersect << " "
36361  << x_average/((double)n_intersect) << std::endl;
36362  internal_point_coord[ihole][0] = x_average/((double)n_intersect);
36363  }
36364  */
36365 
36366  //Set the new hole centre
36367  poly_pt->internal_point() = internal_point_coord[ihole];
36368  //std::cout << "I've had my centre updated to "
36369  // << internal_point_coord[ihole][0]
36370  // << " " << internal_point_coord[ihole][1] << "\n";
36371  }
36372  }
36373 
36374  }
36375  }
36376  } //End of the action (n_hole for)
36377 
36378  if(check_only)
36379  {
36380  // If we make it up to here and we only check then no update is required
36381  return false;
36382  }
36383  else
36384  {
36385  // otherwise indicate whether an actual update was performed
36386  return update_was_performed;
36387  }
36388 
36389  } //End of the loop of internal boundaries
36390 
36391  //======================================================================
36392  /// Create the polylines and fill associate data structures, used when
36393  /// creating from a mesh from polyfiles
36394  //======================================================================
36395  template<class ELEMENT>
36398  const std::string& poly_file_name)
36399  {
36400  // Get the nodes coordinates (the index of the nodes to build the
36401  // polylines is the one used in the node_file_name file)
36402  // Process node file
36403  // -----------------
36404  std::ifstream node_file(node_file_name.c_str(),std::ios_base::in);
36405 
36406  // Check that the file actually opened correctly
36407  if(!node_file.is_open())
36408  {
36409  std::string error_msg("Failed to open node file: ");
36410  error_msg += "\"" + node_file_name + "\".";
36411  throw OomphLibError(error_msg, OOMPH_CURRENT_FUNCTION,
36412  OOMPH_EXCEPTION_LOCATION);
36413  }
36414 
36415  // Read number of nodes
36416  unsigned nnodes;
36417  node_file >> nnodes;
36418 
36419  // Spatial dimension of nodes
36420  unsigned dimension;
36421  node_file >> dimension;
36422 
36423 #ifdef PARANOID
36424  if(dimension!=2)
36425  {
36426  throw OomphLibError("The dimension must be 2\n",
36427  OOMPH_CURRENT_FUNCTION,
36428  OOMPH_EXCEPTION_LOCATION);
36429  }
36430 #endif
36431 
36432  // Storage the nodes vertices
36433  Vector<double> x_node(nnodes);
36434  Vector<double> y_node(nnodes);
36435 
36436  // Number of attributes
36437  unsigned npoint_attributes;
36438  node_file >> npoint_attributes;;
36439 
36440  // Flag for boundary markers
36441  unsigned boundary_markers_flag=0;
36442  node_file >> boundary_markers_flag;
36443 
36444  // Dummy for node number
36445  unsigned dummy_node_number;
36446  // Dummy for node attribute
36447  unsigned dummy_node_attribute;
36448  // Dummy for node boundary
36449  unsigned dummy_node_boundary;
36450 
36451  // Load in nodal posititions, point attributes
36452  // and boundary markers
36453  for(unsigned i=0;i<nnodes;i++)
36454  {
36455  node_file>>dummy_node_number;
36456  node_file>>x_node[i];
36457  node_file>>y_node[i];
36458  for(unsigned j=0;j<npoint_attributes;++j)
36459  {
36460  node_file>>dummy_node_attribute;
36461  }
36462  if(boundary_markers_flag)
36463  {
36464  node_file>>dummy_node_boundary;
36465  }
36466  }
36467  node_file.close();
36468 
36469  // Get the segments information and use that info. to create the
36470  // polylines
36471 
36472  // A map to store the segments associated to a boundary, non sorted
36473  std::map<unsigned,Vector<std::pair<unsigned,unsigned> > >
36474  unsorted_boundary_segments;
36475 
36476  // Independent storage for the boundaries ids found in the segments so that
36477  // the polylines, and therefore polygons be created in the order they appear
36478  // in the polyfile
36479  Vector<unsigned> sorted_boundaries_ids;
36480 
36481  // Process poly file to extract edges
36482  //-----------------------------------
36483 
36484  // Open poly file
36485  std::ifstream poly_file(poly_file_name.c_str(),std::ios_base::in);
36486 
36487  // Check that the file actually opened correctly
36488  if(!poly_file.is_open())
36489  {
36490  std::string error_msg("Failed to open poly file: ");
36491  error_msg += "\"" + poly_file_name + "\".";
36492  throw OomphLibError(error_msg, OOMPH_CURRENT_FUNCTION,
36493  OOMPH_EXCEPTION_LOCATION);
36494  }
36495 
36496  // Number of nodes in poly file --- these will be ignore
36497  unsigned n_node_poly;
36498  poly_file >> n_node_poly;
36499 
36500  // Dimension
36501  poly_file >> dimension;
36502 
36503  // Attribute flag
36504  unsigned attribute_flag;
36505  poly_file >> attribute_flag;
36506 
36507  // Flag for boundary markers
36508  poly_file >> boundary_markers_flag;
36509 
36510  // Ignore node information: Note: No, we can't extract the
36511  // actual nodes themselves from here!
36512  unsigned dummy;
36513  for(unsigned i=0;i<n_node_poly;i++)
36514  {
36515  //Read in (and discard) node number and x and y coordinates
36516  poly_file>>dummy;
36517  poly_file>>dummy;
36518  poly_file>>dummy;
36519  //read in the attributes
36520  for(unsigned j=0;j<attribute_flag;++j)
36521  {
36522  poly_file >> dummy;
36523  }
36524  //read in the boundary marker
36525  if(boundary_markers_flag==1)
36526  {
36527  poly_file>>dummy;
36528  }
36529  }
36530 
36531  // Variable used to read the values from the input file
36532  unsigned read_value;
36533 
36534  // Number of segments
36535  poly_file >> read_value;
36536  const unsigned nglobal_segments = read_value;
36537 
36538  // Boundary marker flag
36539  poly_file >> boundary_markers_flag;
36540 
36541  // Global segment number
36542  unsigned global_segment_number;
36543 
36544  // Node identifier set (used to identify possible internal boundaries)
36545  std::set<unsigned> nodes_ids;
36546 
36547  // Extract information for each segment
36548  for(unsigned i=0;i<nglobal_segments;i++)
36549  {
36550  // Node id on the edge of the segment
36551  unsigned lnode_id=0; // left node
36552  unsigned rnode_id=0; // right node
36553  unsigned bnd_id=0; // boundary id associated to the current segment
36554  poly_file >> global_segment_number;
36555  poly_file >> lnode_id;
36556  poly_file >> rnode_id;
36557  nodes_ids.insert(lnode_id);
36558  nodes_ids.insert(rnode_id);
36559  if(boundary_markers_flag)
36560  {
36561  poly_file >> bnd_id;
36562  }
36563 
36564  // Store the segments info. (use bnd_id - 1 because the nodes and
36565  // elements associated the bnd_id have been associated by external
36566  // methods to bnd_id - 1)
36567  unsorted_boundary_segments[bnd_id-1].push_back(
36568  std::make_pair(lnode_id, rnode_id));
36569 
36570  // Add the boundary id to the vector of boundaries ids only if it
36571  // has not been added, the polylines will be created using this
36572  // order
36573 
36574  // Get the number of boundaries ids currently sorted
36575  const unsigned nsorted_boundaries_ids =
36576  sorted_boundaries_ids.size();
36577  // Flag to know if the boundary id was found
36578  bool boundary_id_found = false;
36579  for (unsigned ib = 0; ib < nsorted_boundaries_ids; ib++)
36580  {
36581  if (sorted_boundaries_ids[ib] == bnd_id - 1)
36582  {
36583  boundary_id_found = true;
36584  break;
36585  } // if (sorted_boundaries_ids[ib] == bnd_id - 1)
36586  } // for (ib < nsorted_boundaries_ids)
36587 
36588  // If th boundary id has not been added, then add it!!!
36589  if (!boundary_id_found)
36590  {
36591  sorted_boundaries_ids.push_back(bnd_id - 1);
36592  } // if (!boundary_id_found)
36593 
36594  }
36595 
36596  // Verify if there are internal boundaries defined, if that is the
36597  // case we can not continue since we are not yet supporting internal
36598  // boundaries defined in polyfiles to created a mesh that may be
36599  // adapted
36600 #ifdef PARANOID
36601  if (nglobal_segments != nodes_ids.size())
36602  {
36603  std::ostringstream error_message;
36604  error_message
36605  << "The number of nodes (" << nodes_ids.size() << ") and segments ("
36606  << nglobal_segments << ") is different.\nThis may mean that there "
36607  << "are internal non-closed boundaries defined in\nthe polyfile. "
36608  << "If you need this feature please use the TriangleMeshPoyLine\n"
36609  << "and TriangleMeshCurviLine objects to define your domain.\n\n";
36610  throw OomphLibError(error_message.str(),
36611  OOMPH_CURRENT_FUNCTION,
36612  OOMPH_EXCEPTION_LOCATION);
36613  }
36614 #endif
36615 
36616  // Now sort the segments associated to a boundary to create a contiguous
36617  // polyline, but first check that the number of found boundaries be the
36618  // same as the current number of boundaries in the mesh
36619  const unsigned nboundary = unsorted_boundary_segments.size();
36620 
36621 #ifdef PARANOID
36622  if (nboundary != this->nboundary())
36623  {
36624  std::ostringstream error_message;
36625  error_message
36626  << "The number of boundaries on the mesh (" << this->nboundary()
36627  << ") is different from the number of\nboundaries read from the "
36628  << "polyfiles (" << unsorted_boundary_segments.size() << ")!!!\n\n\n";
36629  throw OomphLibError(error_message.str(),
36630  OOMPH_CURRENT_FUNCTION,
36631  OOMPH_EXCEPTION_LOCATION);
36632  }
36633 #endif
36634 
36635  // Get the number of sorted boundaries ids and check that it matches
36636  // with the total number of boundaries
36637  const unsigned nsorted_boundaries_ids =
36638  sorted_boundaries_ids.size();
36639 #ifdef PARANOID
36640  if (nsorted_boundaries_ids != this->nboundary())
36641  {
36642  std::ostringstream error_message;
36643  error_message
36644  << "The number of boundaries on the mesh (" << this->nboundary()
36645  << ") is different from the number of\nsorted boundaries ids read "
36646  << "from the polyfiles (" << nsorted_boundaries_ids << ")!!!\n\n\n";
36647  throw OomphLibError(error_message.str(),
36648  OOMPH_CURRENT_FUNCTION,
36649  OOMPH_EXCEPTION_LOCATION);
36650  }
36651 #endif
36652 
36653  // Sorted segments (to create a polyline -- boundary)
36654  std::map<unsigned, std::list<unsigned> > sorted_boundary_segments;
36655 
36656  // Go through all the found boundaries
36657  std::map<unsigned,Vector<std::pair<unsigned,unsigned> > >::iterator it;
36658 
36659  for (it = unsorted_boundary_segments.begin();
36660  it != unsorted_boundary_segments.end();
36661  it++)
36662  {
36663  // Get the current boundary id, only look for the segments
36664  // associated with this boundary
36665  const unsigned bnd_id = (*it).first;
36666  Vector<std::pair<unsigned, unsigned> > segments_edges = (*it).second;
36667 
36668  // Now sort the segments associated to this boundary
36669  std::map<std::pair<unsigned, unsigned>, bool> segment_done;
36670  const unsigned nsegments = segments_edges.size();
36671 
36672  // Sorted nodes for the current segment
36673  std::list<unsigned> sorted_segments;
36674 
36675  // Get the left and right node of the zero segment
36676  unsigned left_node_id = segments_edges[0].first;
36677  unsigned right_node_id = segments_edges[0].second;
36678 
36679  // ... and add it to the sorted segments structure
36680  sorted_segments.push_back(left_node_id);
36681  sorted_segments.push_back(right_node_id);
36682 
36683  // Mark the current segment as done
36684  segment_done[segments_edges[0]] = true;
36685 
36686  // Set the number of sorted segments
36687  unsigned nsorted_segments = 1;
36688 
36689  while(nsorted_segments < nsegments)
36690  {
36691  for (unsigned i = 1; i < nsegments; i++)
36692  {
36693  // Check if the i-th segments has been done
36694  if (!segment_done[segments_edges[i]])
36695  {
36696  // Get the left and right node id
36697  unsigned current_left_node_id = segments_edges[i].first;
36698  unsigned current_right_node_id = segments_edges[i].second;
36699 
36700  // Now check if the current segment can be added to the left
36701  // or right side of the sorted segments
36702  if (current_left_node_id == right_node_id)
36703  {
36704  // Add the current_right_node_id to the right of the sorted
36705  // segments
36706  sorted_segments.push_back(current_right_node_id);
36707  // Increase the number of sorted segments
36708  nsorted_segments++;
36709  // Mark the segment as done
36710  segment_done[segments_edges[i]] = true;
36711  // Update the right most node
36712  right_node_id = current_right_node_id;
36713  // Break the for loop
36714  break;
36715  }
36716  else if (current_right_node_id == left_node_id)
36717  {
36718  // Add the current_left_node_id to the left of the sorted
36719  // segments
36720  sorted_segments.push_front(current_left_node_id);
36721  // Increase the number of sorted segments
36722  nsorted_segments++;
36723  // Mark the segment as done
36724  segment_done[segments_edges[i]] = true;
36725  // Update the left most node
36726  left_node_id = current_left_node_id;
36727  // Break the for loop
36728  break;
36729  }
36730  else if (current_left_node_id == left_node_id)
36731  {
36732  // Add the current_right_node_id to the left of the sorted
36733  // segments
36734  sorted_segments.push_front(current_right_node_id);
36735  // Increase the number of sorted segments
36736  nsorted_segments++;
36737  // Mark the segment as done
36738  segment_done[segments_edges[i]] = true;
36739  // Update the left most node
36740  left_node_id = current_right_node_id;
36741  // Break the for loop
36742  break;
36743  }
36744  else if (current_right_node_id == right_node_id)
36745  {
36746  // Add the current_left_node_id to the right of the sorted
36747  // segments
36748  sorted_segments.push_back(current_left_node_id);
36749  // Increase the number of sorted segments
36750  nsorted_segments++;
36751  // Mark the segment as done
36752  segment_done[segments_edges[i]] = true;
36753  // Update the left most node
36754  right_node_id = current_left_node_id;
36755  // Break the for loop
36756  break;
36757  }
36758  } // if (!segment_done[segments_edges[i]])
36759  } // for (i < nsegments)
36760  } // while(nsorted_segments < nsegments)
36761 
36762  sorted_boundary_segments[bnd_id] = sorted_segments;
36763 
36764  } // for (unsorted_boundary_segments.begin();
36765  // unsorted_boundary_segments.end())
36766 
36767 #ifdef PARANOID
36768  if (sorted_boundary_segments.size() != this->nboundary())
36769  {
36770  std::ostringstream error_message;
36771  error_message
36772  << "The number of boundaries on the mesh (" << this->nboundary()
36773  << ") is different from the number\nof sorted boundaries to create the "
36774  << "polylines (" << sorted_boundary_segments.size() << ")\n\n";
36775  throw OomphLibError(error_message.str(),
36776  OOMPH_CURRENT_FUNCTION,
36777  OOMPH_EXCEPTION_LOCATION);
36778  }
36779 #endif
36780 
36781  // Now we have the sorted nodes, we can create the polylines by
36782  // getting the vertices of the nodes
36783  Vector<TriangleMeshPolyLine*> polylines_pt(nboundary);
36784  unsigned current_polyline = 0;
36785 
36786  // Go through the sorted boundaries using the sorted boundaries ids
36787  for (unsigned ib = 0; ib < nsorted_boundaries_ids; ib++)
36788  {
36789  // Get the boundary id from the vector of sorted boundaries ids
36790  const unsigned bnd_id = sorted_boundaries_ids[ib];
36791 
36792  // Create a vector representation for ease to use
36793  // Get the vertices of the nodes that create the boundary / polyline
36794  Vector<unsigned> nodes_ids;
36795  for (std::list<unsigned>::iterator it_list =
36796  sorted_boundary_segments[bnd_id].begin();
36797  it_list != sorted_boundary_segments[bnd_id].end();
36798  it_list++)
36799  {nodes_ids.push_back((*it_list));}
36800 
36801  // Get the number of vertices for the polyline
36802  const unsigned nvertices = nodes_ids.size();
36803 
36804  // The storage for the vertices
36805  Vector<Vector<double> > vertices(nvertices);
36806 
36807  // Now get the vertices of the nodes of the current boundary
36808  for (unsigned i = 0; i < nvertices; i++)
36809  {
36810  // Get the vertices
36811  vertices[i].resize(2);
36812  vertices[i][0] = x_node[nodes_ids[i]-1];
36813  vertices[i][1] = y_node[nodes_ids[i]-1];
36814  }
36815 
36816  // Now create the polyline
36817 
36818  // Note: The bnd_id is the real bnd_id (from the input file) - 1
36819  // since nodes and elements of the current boundary have been
36820  // associated to bnd_id - 1)
36821  polylines_pt[current_polyline] =
36822  new TriangleMeshPolyLine(vertices, bnd_id);
36823 
36824  // Updates bnd_id<--->curve section map
36825  this->Boundary_curve_section_pt[bnd_id] =
36826  dynamic_cast<TriangleMeshCurveSection*>(polylines_pt[current_polyline]);
36827 
36828  // Increase the index for the polyline storage
36829  current_polyline++;
36830 
36831  } // for (it_sorted = sorted_boundary_segments.begin();
36832  // it_sorted != sorted_boundary_segments.end())
36833 
36834  // Now create the polygons or closed curves
36835  // Sort the polylines to create polygons
36836  unsigned nsorted_polylines = 0;
36837 
36838  // Number of created polygons
36839  unsigned npolygons = 0;
36840 
36841  // Storage for the polygons
36842  Vector<TriangleMeshPolygon*> polygons_pt;
36843 
36844  // Mark the already done polylines
36845  std::map<unsigned, bool> polyline_done;
36846  while(nsorted_polylines < nboundary)
36847  {
36848  // Storage for the curve sections that create a polygon
36849  std::list<TriangleMeshCurveSection*> sorted_curve_sections_pt;
36850 
36851  unsigned init_poly = 0;
36852 #ifdef PARANOID
36853  bool found_root_polyline = false;
36854 #endif
36855  // Get the left and right node of the current polyline
36856  for (unsigned i = 0; i < nboundary; i++)
36857  {
36858  if (!polyline_done[i])
36859  {
36860  init_poly = i;
36861  // Increase the number of sorted polylines
36862  nsorted_polylines++;
36863 #ifdef PARANOID
36864  // Mark as found the root polyline
36865  found_root_polyline = true;
36866 #endif
36867  // Mark the polyline as done
36868  polyline_done[i] = true;
36869  // Add the polyline to the curve sections storage
36870  sorted_curve_sections_pt.push_back(polylines_pt[i]);
36871  // Break the loop to set we have found a root polyline
36872  break;
36873  }
36874  }
36875 
36876 #ifdef PARANOID
36877  if (!found_root_polyline)
36878  {
36879  std::ostringstream error_message;
36880  error_message
36881  << "Was not possible to found the root polyline to create polygons\n\n";
36882  throw OomphLibError(error_message.str(),
36883  OOMPH_CURRENT_FUNCTION,
36884  OOMPH_EXCEPTION_LOCATION);
36885  }
36886 #endif
36887 
36888  // Get the associated boundary to the current polyline
36889  const unsigned bnd_id = polylines_pt[init_poly]->boundary_id();
36890  // Get the initial and final node id of the current polyline
36891  unsigned left_node_id = sorted_boundary_segments[bnd_id].front();
36892  unsigned right_node_id = sorted_boundary_segments[bnd_id].back();
36893 
36894  // Flag to know that we already have a closed polygon
36895  bool closed_polygon = false;
36896 
36897  do
36898  {
36899  // Go through all the polylines
36900  for (unsigned i = init_poly; i < nboundary; i++)
36901  {
36902  // Check that the polyline has not been currently done
36903  if (!polyline_done[i])
36904  {
36905  // Get the initial and final nodes id of the current polyline
36906 
36907  // Get the associated boundary to the current polyline
36908  const unsigned cbnd_id = polylines_pt[i]->boundary_id();
36909  // Get the initial and final node id of the current polyline
36910  unsigned cleft_node_id = sorted_boundary_segments[cbnd_id].front();
36911  unsigned cright_node_id = sorted_boundary_segments[cbnd_id].back();
36912 
36913  // Check if the polyline goes to the left or right of the
36914  // current sorted polylines
36915  if (cleft_node_id == right_node_id)
36916  {
36917  // Add the polyline to the curve section storage
36918  sorted_curve_sections_pt.push_back(polylines_pt[i]);
36919  // Mark the polyline as done
36920  polyline_done[i] = true;
36921  // Update the right node
36922  right_node_id = cright_node_id;
36923  // Increase the number of done polyines
36924  nsorted_polylines++;
36925  // Break the for loop
36926  break;
36927  }
36928  else if (cright_node_id == left_node_id)
36929  {
36930  // Add the polyline to the curve section storage
36931  sorted_curve_sections_pt.push_front(polylines_pt[i]);
36932  // Mark the polyline as done
36933  polyline_done[i] = true;
36934  // Update the right node
36935  left_node_id = cleft_node_id;
36936  // Increase the number of done polyines
36937  nsorted_polylines++;
36938  // Break the for loop
36939  break;
36940  }
36941  else if (cleft_node_id == left_node_id)
36942  {
36943  // First reverse the polyline
36944  polylines_pt[i]->reverse();
36945  // Add the polyline to the curve section storage
36946  sorted_curve_sections_pt.push_front(polylines_pt[i]);
36947  // Mark the polyline as done
36948  polyline_done[i] = true;
36949  // Update the right node
36950  left_node_id = cright_node_id;
36951  // Increase the number of done polyines
36952  nsorted_polylines++;
36953  // Break the for loop
36954  break;
36955  }
36956  else if (cright_node_id == right_node_id)
36957  {
36958  // First reverse the polyline
36959  polylines_pt[i]->reverse();
36960  // Add the polyline to the curve section storage
36961  sorted_curve_sections_pt.push_back(polylines_pt[i]);
36962  // Mark the polyline as done
36963  polyline_done[i] = true;
36964  // Update the right node
36965  right_node_id = cleft_node_id;
36966  // Increase the number of done polyines
36967  nsorted_polylines++;
36968  // Break the for loop
36969  break;
36970  }
36971  } // if (!polyline_done[i])
36972 
36973  } // for (i < nboundary)
36974 
36975  // We have created a polygon
36976  if (left_node_id == right_node_id)
36977  {
36978  // Set the flag as true
36979  closed_polygon = true;
36980  }
36981 
36982  }while(nsorted_polylines < nboundary && !closed_polygon);
36983 
36984 #ifdef PARANOID
36985  if (!closed_polygon)
36986  {
36987  std::ostringstream error_message;
36988  error_message
36989  << "It was not possible to create a closed curve, these are the "
36990  << "vertices of the already sorted polylines\n\n";
36991  unsigned cpolyline = 0;
36992  for (std::list<TriangleMeshCurveSection*>::iterator it_list =
36993  sorted_curve_sections_pt.begin();
36994  it_list != sorted_curve_sections_pt.end();
36995  it_list++)
36996  {
36997  error_message << "Polyline (" << cpolyline << ")\n";
36998  TriangleMeshPolyLine *tmp_poly_pt =
36999  dynamic_cast<TriangleMeshPolyLine*>((*it_list));
37000  const unsigned nvertex = tmp_poly_pt->nvertex();
37001  for (unsigned v = 0; v < nvertex; v++)
37002  {
37003  error_message <<"("<<tmp_poly_pt->vertex_coordinate(v)[0]
37004  <<", "<<tmp_poly_pt->vertex_coordinate(v)[1]<<")\n";
37005  }
37006  error_message << "\n";
37007  cpolyline++;
37008  }
37009  throw OomphLibError(error_message.str(),
37010  OOMPH_CURRENT_FUNCTION,
37011  OOMPH_EXCEPTION_LOCATION);
37012  }
37013 #endif
37014 
37015  // Create a vector version to create the polygon from the sorted
37016  // polyines
37017  Vector<TriangleMeshCurveSection*> tmp_sorted_curve_sections_pt;
37018  for (std::list<TriangleMeshCurveSection*>::iterator it_list =
37019  sorted_curve_sections_pt.begin();
37020  it_list != sorted_curve_sections_pt.end();
37021  it_list++)
37022  {tmp_sorted_curve_sections_pt.push_back((*it_list));}
37023 
37024  // Create a new polygon by using the new created polylines
37025  TriangleMeshPolygon *polygon_pt =
37026  new TriangleMeshPolygon(tmp_sorted_curve_sections_pt);
37027 
37028  // Keep track of new created polygons that need to be deleted!!!
37029  this->Free_polygon_pt.insert(polygon_pt);
37030 
37031  // Store the polygon in the polygons storages
37032  polygons_pt.push_back(polygon_pt);
37033 
37034  npolygons++;
37035 
37036  } // while(nsorted_polylines < nboundary)
37037 
37038  // ------------------------------------------------------------------
37039  // Before filling the data structures we need to identify the outer
37040  // closed boundary and the inner closed boundaries.
37041  // If the nodes are not in order we throw a warning message
37042 
37043  // Index for the polygon that is currently considered as the outer
37044  // boundary
37045  unsigned index_outer = 0;
37046 
37047  for (unsigned idx_outer = 0; idx_outer < npolygons; idx_outer++)
37048  {
37049  // Get the vertices of the outer boundary
37050  Vector<Vector<double> > outer_vertex_coordinates;
37051 
37052  // Flag to know if ALL the inner closed boundaries are inside the
37053  // outer closed boundary
37054  bool all_inner_inside = true;
37055 
37056  // Number of polylines of the outer boundary
37057  const unsigned nouter_polylines = polygons_pt[idx_outer]->npolyline();
37058  for (unsigned p = 0; p < nouter_polylines; p++)
37059  {
37060  TriangleMeshPolyLine* tmp_poly_pt =
37061  polygons_pt[idx_outer]->polyline_pt(p);
37062  const unsigned nvertex = tmp_poly_pt->nvertex();
37063  for (unsigned v = 0; v < nvertex; v++)
37064  {
37065  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37066  outer_vertex_coordinates.push_back(current_vertex);
37067  } // for (v < nvertex)
37068  } // for (p < nouter_polylines)
37069 
37070  // Now get the vertices for the inner boundaries
37071 
37072  // First get the number of inner closed boundaries (polygons size
37073  // minus one because one of the polygons is considered to be the
37074  // outer closed boundary
37075  const unsigned ninner_polygons = polygons_pt.size() - 1;
37076 
37077  // Store the vertices of the inner closed boundaries
37078  Vector<Vector<Vector<double> > > inner_vertex_coordinates(ninner_polygons);
37079  // Get all the vertices of the inner closed boundaries
37080  for (unsigned i = 0; i <= ninner_polygons; i++)
37081  {
37082  if (i != idx_outer)
37083  {
37084  // Number of polylines of the current internal closed boundary
37085  const unsigned ninner_polylines = polygons_pt[i]->npolyline();
37086  for (unsigned p = 0; p < ninner_polylines; p++)
37087  {
37088  TriangleMeshPolyLine* tmp_poly_pt = polygons_pt[i]->polyline_pt(p);
37089  const unsigned nvertex = tmp_poly_pt->nvertex();
37090  for (unsigned v = 0; v < nvertex; v++)
37091  {
37092  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37093  if (i < idx_outer)
37094  {
37095  inner_vertex_coordinates[i].push_back(current_vertex);
37096  }
37097  else if (i > idx_outer)
37098  {
37099  inner_vertex_coordinates[i-1].push_back(current_vertex);
37100  }
37101  } // for (v < nvertex)
37102 
37103  } // for (p < ninner_polylines)
37104 
37105  } // if (i != index_outer)
37106 
37107  } // for (i <= ninner_polygons)
37108 
37109  // Now check that ALL the vertices of ALL the internal closed
37110  // boundaries are inside the outer closed boundary
37111  for (unsigned i = 0; i < ninner_polygons; i++)
37112  {
37113  // Get the number of vertices in the current internal closed
37114  // boundary
37115  const unsigned nvertex_internal = inner_vertex_coordinates[i].size();
37116  for (unsigned v = 0; v < nvertex_internal; v++)
37117  {
37118  // Get a vertex in the current internal closed boundary
37119  Vector<double> current_point = inner_vertex_coordinates[i][v];
37120  all_inner_inside &=
37121  this->is_point_inside_polygon_helper(outer_vertex_coordinates,
37122  current_point);
37123 
37124  // Check if we should continue checking for more points inside
37125  // the current proposed outer boundary
37126  if (!all_inner_inside)
37127  {
37128  // Break the "for" for the vertices
37129  break;
37130  }
37131 
37132  } // for (v < nvertex_internal)
37133 
37134  // Check if we should continue checking for more inner closed
37135  // boundaries inside the current proposed outer boundary
37136  if (!all_inner_inside)
37137  {
37138  // Break the "for" for the inner boundaries
37139  break;
37140  }
37141 
37142  } // for (i < ninner_polygons)
37143 
37144  // Check if all the vertices of all the polygones are inside the
37145  // current proposed outer boundary
37146  if (all_inner_inside)
37147  {
37148  index_outer = idx_outer;
37149  break;
37150  }
37151 
37152  } // for (idx_outer < npolygons)
37153 
37154 #ifdef PARANOID
37155  // Check if the first nodes listed in the polyfiles correspond to
37156  // the outer boundary, if that is not the case then throw a warning
37157  // message
37158  if (index_outer != 0)
37159  {
37160  std::ostringstream warning_message;
37161  warning_message
37162  << "The first set of nodes listed in the input polyfiles does not\n"
37163  << "correspond to the outer closed boundary. This may lead to\n"
37164  << "problems at the adaptation stage if the holes coordinates\n"
37165  << "are no correctly associated to the inner closed boundaries.\n"
37166  << "You can check the generated mesh by calling the output() method\n"
37167  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37168  OomphLibWarning(warning_message.str(),
37169  OOMPH_CURRENT_FUNCTION,
37170  OOMPH_EXCEPTION_LOCATION);
37171  } // if (index_outer != 0)
37172 #endif
37173 
37174  // ------------------------------------------------------------------
37175  // Now fill the data structures
37176 
37177  // Store outer polygon
37178  // We are assuming there is only one outer polygon
37179  this->Outer_boundary_pt.resize(1);
37180  this->Outer_boundary_pt[0] = polygons_pt[index_outer];
37181 
37182  this->Internal_polygon_pt.resize(npolygons-1);
37183  for (unsigned i = 0; i < npolygons; i++)
37184  {
37185  if (i != index_outer)
37186  {
37187  if (i < index_outer)
37188  {
37189  // Store internal polygons by copy constructor
37190  this->Internal_polygon_pt[i] = polygons_pt[i];
37191  }
37192  else if (i > index_outer)
37193  {
37194  // Store internal polygons by copy constructor
37195  this->Internal_polygon_pt[i-1] = polygons_pt[i];
37196  }
37197  } // if (i != index_outer)
37198  } // for (i < npolygons)
37199 
37200  // Before assigning the hole vertex coordinate to the inner closed
37201  // boundaries check that the holes are listed in orderm if that is
37202  // not the case the associate each hole vertex coordinate to the
37203  // inner closed boundaries
37204 
37205  // Store the vertices of the inner closed boundaries
37206  Vector<Vector<Vector<double> > > inner_vertex_coordinates(npolygons-1);
37207  // Get all the vertices of the inner closed boundaries
37208  for (unsigned i = 0; i < npolygons-1; i++)
37209  {
37210  // Number of polylines of the current internal closed boundary
37211  const unsigned ninner_polylines =
37212  this->Internal_polygon_pt[i]->npolyline();
37213  for (unsigned p = 0; p < ninner_polylines; p++)
37214  {
37215  TriangleMeshPolyLine* tmp_poly_pt =
37216  this->Internal_polygon_pt[i]->polyline_pt(p);
37217  // Number of vertices of the current polyline in the current
37218  // internal closed polygon
37219  const unsigned nvertex = tmp_poly_pt->nvertex();
37220  for (unsigned v = 0; v < nvertex; v++)
37221  {
37222  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37223  inner_vertex_coordinates[i].push_back(current_vertex);
37224  } // for (v < nvertex)
37225 
37226  } // for (p < ninner_polylines)
37227 
37228  } // for (i <= ninner_polygons)
37229 
37230  // Holes information
37231  unsigned nholes;
37232  poly_file >> nholes;
37233 
37234 #ifdef PARANOID
37235  if (npolygons > 1 && (npolygons - 1) != nholes)
37236  {
37237  std::ostringstream error_message;
37238  error_message
37239  << "The number of holes (" << nholes << ") does not correspond "
37240  << "with the number\nof internal polygons ("
37241  << npolygons - 1 <<")\n\n"
37242  << "Using polyfiles as input does not currently allows the\n"
37243  << "definition of more than one outer polygon\n\n";
37244  throw OomphLibError(error_message.str(),
37245  OOMPH_CURRENT_FUNCTION,
37246  OOMPH_EXCEPTION_LOCATION);
37247  }
37248 #endif
37249 
37250  // Storage for the holes
37251  Vector<Vector<double> > hole_coordinates(nholes);
37252 
37253  // Dummy for hole number
37254  unsigned dummy_hole;
37255  // Loop over the holes to get centre coords
37256  for(unsigned ihole=0;ihole<nholes;ihole++)
37257  {
37258  hole_coordinates[ihole].resize(2);
37259  // Read the centre value
37260  poly_file >> dummy_hole;
37261  poly_file >> hole_coordinates[ihole][0];
37262  poly_file >> hole_coordinates[ihole][1];
37263  }
37264 
37265  // Vector that store the index of the hole coordinate that
37266  // correspond to each internal closed polygon
37267  Vector<unsigned> index_hole_of_internal_polygon(npolygons-1);
37268  std::map<unsigned, bool> hole_done;
37269 
37270  // Now associate each hole vertex to a corresponding internal closed
37271  // polygon
37272  for (unsigned i = 0; i < npolygons-1; i++)
37273  {
37274  // Find which hole is associated to each internal closed boundary
37275  for (unsigned h = 0; h < nholes; h++)
37276  {
37277  // If the hole has not been previously associated
37278  if (!hole_done[h])
37279  {
37280  // Get the hole coordinate
37281  Vector<double> current_point = hole_coordinates[h];
37282 
37283  const bool hole_in_polygon =
37284  this->is_point_inside_polygon_helper(inner_vertex_coordinates[i],
37285  current_point);
37286 
37287  // If the hole is inside the polygon
37288  if (hole_in_polygon)
37289  {
37290  // Mark the hole as done
37291  hole_done[h] = true;
37292  // Associate the current hole with the current inner closed
37293  // boundary
37294  index_hole_of_internal_polygon[i] = h;
37295  // Break the search
37296  break;
37297  }
37298 
37299  } // if (!hole_done[h])
37300 
37301  } // for (h < nholes)
37302 
37303  } // for (i < npolygons-1)
37304 
37305 #ifdef PARANOID
37306  if (hole_done.size() != npolygons-1)
37307  {
37308  std::ostringstream error_message;
37309  error_message
37310  << "Not all the holes were associated to an internal closed boundary\n"
37311  << "Only ("<<hole_done.size()<<") holes were assigned for a total of\n"
37312  << "(" << npolygons-1 << ") internal closed boundaries.\n"
37313  << "You can check the generated mesh by calling the output() method\n"
37314  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37315  throw OomphLibError(error_message.str(),
37316  OOMPH_CURRENT_FUNCTION,
37317  OOMPH_EXCEPTION_LOCATION);
37318  } // if (index_hole != ihole)
37319 #endif
37320 
37321  // Assign the holes coordinates to the internal polygons
37322  for (unsigned ihole = 0; ihole < nholes; ihole++)
37323  {
37324  // Get the index hole of the current internal closed polygon
37325  const unsigned index_hole = index_hole_of_internal_polygon[ihole];
37326 #ifdef PARANOID
37327  // Check if the hole index is the same as the internal closed
37328  // boundary, it means that the holes were listed in the same order
37329  // as the nodes of the internal closed boundaries
37330  if (index_hole != ihole)
37331  {
37332  std::ostringstream error_message;
37333  error_message
37334  << "The hole vertices coordinates are not listed in the same order\n"
37335  << "as the nodes that define the internal closed boundaries.\n"
37336  << "This may lead to problems in case that the holes coordinates\n"
37337  << "were no properly assigned to the internal closed boundaries.\n"
37338  << "You can check the generated mesh by calling the output() method\n"
37339  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37340  throw OomphLibError(error_message.str(),
37341  OOMPH_CURRENT_FUNCTION,
37342  OOMPH_EXCEPTION_LOCATION);
37343  } // if (index_hole != ihole)
37344 #endif
37345 
37346  // Set the hole coordinate for the internal polygon
37347  this->Internal_polygon_pt[ihole]->internal_point() =
37348  hole_coordinates[index_hole];
37349  }
37350 
37351  // Ignore the first line with structure description
37352  poly_file.ignore(80,'\n');
37353 
37354  // Regions information
37355  unsigned nregions;
37356 
37357  // Extract regions information
37358  // But first check if there are regions or not
37359  std::string regions_info_string;
37360 
37361  // Read line up to termination sign
37362  getline(poly_file, regions_info_string);
37363 
37364  // Check if the read string is a number or a comment wrote by triangle,
37365  // if it is a number then that is the number of regions
37366  if (isdigit(regions_info_string.c_str()[0]))
37367  {
37368  nregions = std::atoi(regions_info_string.c_str());
37369  }
37370  else
37371  {
37372  nregions = 0;
37373  }
37374 
37375  // The regions coordinates
37376  std::map<unsigned, Vector<double> > regions_coordinates;
37377 
37378  // Dummy for regions number
37379  unsigned dummy_region;
37380 
37381  unsigned region_id;
37382 
37383  // Loop over the regions to get their coords
37384  for(unsigned iregion=0;iregion<nregions;iregion++)
37385  {
37386  Vector<double> tmp_region_coordinates(2);
37387  // Read the regions coordinates
37388  poly_file >> dummy_region;
37389  poly_file >> tmp_region_coordinates[0];
37390  poly_file >> tmp_region_coordinates[1];
37391  poly_file >> region_id;
37392  regions_coordinates[region_id].resize(2);
37393  regions_coordinates[region_id][0] = tmp_region_coordinates[0];
37394  regions_coordinates[region_id][1] = tmp_region_coordinates[1];
37395 
37396  // Ignore the first line with structure description
37397  poly_file.ignore(80,'\n');
37398 
37399  // Verify if not using the default region number (zero)
37400  if (region_id == 0)
37401  {
37402  std::ostringstream error_message;
37403  error_message << "Please use another region id different from zero.\n"
37404  << "It is internally used as the default region number.\n";
37405  throw OomphLibError(error_message.str(),
37406  OOMPH_CURRENT_FUNCTION,
37407  OOMPH_EXCEPTION_LOCATION);
37408  }
37409 
37410  }
37411 
37412  // Store the extra regions coordinates
37413  this->Regions_coordinates = regions_coordinates;
37414 
37415  poly_file.close();
37416 
37417  }
37418 
37419 //======================================================================
37420 /// \short Updates the polygon but using the elements area instead of
37421 /// the default refinement and unrefinement methods
37422 //======================================================================
37423 template <class ELEMENT>
37426  const Vector<double> &target_area)
37427 {
37428  // Verify that there was a change on the polygon representation
37429  unsigned update_was_performed = false;
37430 
37431  const unsigned nele = this->nelement();
37432 
37433  // - Get the vertices along the boundaries and for each element identify
37434  // its associated target error.
37435  // - Get face mesh representation of each polyline.
37436  // - Get the vertices with the help of face elements.
37437  // - Find the global index in the mesh of the face element and use
37438  // it to get its associated target area
37439 
37440  // Get the face mesh representation
37441  Vector<Mesh*> face_mesh_pt;
37442  get_face_mesh_representation(polygon_pt,face_mesh_pt);
37443 
37444  // Create vertices of the polylines by using the vertices of the
37445  // FaceElements
37446  Vector<double> vertex_coord(3); // zeta,x,y
37447  Vector<double> bound_left(1);
37448  Vector<double> bound_right(1);
37449 
37450  unsigned n_polyline = polygon_pt->npolyline();
37451 
37452  // Go for each polyline
37453  for(unsigned p = 0; p < n_polyline; p++)
37454  {
37455  // Get the MeshAsGeomObject representation just once per polyline,
37456  // this object is only used by the
37457  // refine_boundary_constrained_by_target_area() method. We get it
37458  // here to ensure that all processors (in a distributed context)
37459  // get this representation just once, and because an AllToAll MPI
37460  // communication is used in this calling
37461  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt[p]);
37462 
37463  // Set of coordinates on the boundary
37464  // Set entries are ordered on first entry in vector which stores
37465  // the boundary coordinate so the vertices come out in order!
37466  std::set<Vector<double> > vertex_nodes;
37467 
37468  // Vector to store the vertices, transfer the sorted vertices from the
37469  // set to this vector, --- including the z-value ---
37470  Vector<Vector<double> > tmp_vector_vertex_node;
37471 
37472  // Vector to store the coordinates of the polylines, same as the
37473  // tmp_vector_vertex_node vector (after adding more nodes) but
37474  // --- without the z-value ---, used to re-generate the polylines
37475  Vector<Vector<double> > vector_vertex_node;
37476 
37477 #ifdef OOMPH_HAS_MPI
37478  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
37479  // Set of coordinates that are on the boundary (splitted boundary version)
37480  // The first vector is used to allocate the points for each sub-boundary
37481  // Set entries are ordered on first entry in vector which stores
37482  // the boundary coordinate so the vertices come out in order!
37483  Vector<std::set<Vector<double> > >sub_vertex_nodes;
37484 
37485  // Vector to store the vertices, transfer the sorted vertices from the
37486  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
37487  Vector<Vector<Vector<double> > >sub_tmp_vector_vertex_node;
37488 
37489  // Vector to store the coordinates of the polylines that will represent
37490  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
37491  // but --- without the z-value ---, used to generate the sub-polylines
37492  Vector<Vector<Vector<double> > > sub_vector_vertex_node;
37493  // --------- Stuff to deal with splitted boundaries ----------- End ------
37494 #endif
37495 
37496  //Get the boundary id
37497  const unsigned bound = polygon_pt->curve_section_pt(p)->boundary_id();
37498 
37499  // Get the chunk number
37500  const unsigned chunk = polygon_pt->curve_section_pt(p)->boundary_chunk();
37501 
37502  /// Use a vector of vector for vertices and target areas to deal
37503  /// with the cases when the boundaries are split by the
37504  /// distribution process
37505 
37506  // Loop over the face elements (ordered) and add their vertices
37507  const unsigned nface_element = face_mesh_pt[p]->nelement();
37508 
37509  // Store the non halo face elements, the ones from which we will
37510  // get the vertices
37511  Vector<FiniteElement*> non_halo_face_element_pt;
37512 
37513  // Map to store the index of the face element on a boundary
37514  std::map<FiniteElement*,unsigned> face_element_index_on_boundary;
37515 
37516  for(unsigned ef=0;ef<nface_element;++ef)
37517  {
37518  FiniteElement* ele_face_pt = face_mesh_pt[p]->finite_element_pt(ef);
37519 #ifdef OOMPH_HAS_MPI
37520  // Skip the halo elements if working with a distributed mesh
37521  if (this->is_mesh_distributed() && ele_face_pt->is_halo())
37522  {continue;}
37523 #endif
37524  // Add the face element to the vector
37525  non_halo_face_element_pt.push_back(ele_face_pt);
37526  face_element_index_on_boundary[ele_face_pt] = ef;
37527  }
37528 
37529  // Get the number of non halo face element
37530  const unsigned nnon_halo_face_element = non_halo_face_element_pt.size();
37531 
37532  // Map to know the already sorted face elements
37533  std::map<FiniteElement*,bool> face_element_done;
37534 
37535  // Number of done face elements
37536  unsigned nsorted_face_elements = 0;
37537 
37538 #ifdef OOMPH_HAS_MPI
37539  // Counter for sub_boundaries
37540  unsigned nsub_boundaries = 0;
37541 #endif // #ifdef OOMPH_HAS_MPI
37542 
37543  // Continue until all the face elements have been sorted
37544  // While to deal with split boundaries cases
37545  while(nsorted_face_elements < nnon_halo_face_element)
37546  {
37547  // Get and initial face element
37548  FiniteElement* ele_face_pt = 0;
37549 #ifdef PARANOID
37550  bool found_initial_face_element = false;
37551 #endif
37552 
37553  unsigned iface = 0;
37554  for (iface = 0; iface < nnon_halo_face_element; iface++)
37555  {
37556  ele_face_pt = non_halo_face_element_pt[iface];
37557  // If not done then take it as initial face element
37558  if (!face_element_done[ele_face_pt])
37559  {
37560 #ifdef PARANOID
37561  found_initial_face_element = true;
37562 #endif
37563  nsorted_face_elements++;
37564  iface++;
37565  break;
37566  }
37567  }
37568 
37569 #ifdef PARANOID
37570  if (!found_initial_face_element)
37571  {
37572  std::ostringstream error_message;
37573  error_message
37574  <<"Could not find an initial face element for the current segment\n";
37575  // << "----- Possible memory leak -----\n";
37576  throw OomphLibError(error_message.str(),
37577  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37578  OOMPH_EXCEPTION_LOCATION);
37579  }
37580 #endif
37581 
37582  // Local set of coordinates that are on the boundary
37583  // Set entries are ordered on first entry in vector which stores
37584  // the boundary coordinate so the vertices come out in order!
37585  std::set<Vector<double> > local_vertex_nodes;
37586 
37587  // Vector to store the vertices, transfer the sorted vertices from the
37588  // set (local) to this vector (local), --- including the z-value ---
37589  Vector<Vector<double> > local_tmp_vector_vertex_node;
37590 
37591  // Vector to store the target areas, uses the same approach as the
37592  // set for the local_vertex_nodes, ordered on first entry
37593  std::set<Vector<double> > sorted_target_areas;
37594 
37595  // Vector to store the target areas, used to transfer the sorted target
37596  // areas from "local_sorted_target_areas" set
37597  Vector<double> tmp_sorted_target_areas;
37598 
37599  // -----------------------------------------------------------------
37600  // Add the vertices of the initial face element to the set of
37601  // local sorted vertices
37602  // -----------------------------------------------------------------
37603  unsigned nnode = ele_face_pt->nnode();
37604  // Add the left-hand node to the set:
37605  // Boundary coordinate
37606  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
37607  vertex_coord[0] = bound_left[0];
37608 
37609  // Actual coordinates
37610  for(unsigned i=0;i<2;i++)
37611  {
37612  vertex_coord[i+1] = ele_face_pt->node_pt(0)->x(i);
37613  }
37614  local_vertex_nodes.insert(vertex_coord);
37615 
37616  // Add the right-hand nodes to the set:
37617  // Boundary coordinate
37618  ele_face_pt->node_pt(nnode-1)->
37619  get_coordinates_on_boundary(bound,bound_right);
37620  vertex_coord[0] = bound_right[0];
37621 
37622  // Actual coordinates
37623  for(unsigned i=0;i<2;i++)
37624  {
37625  vertex_coord[i+1] = ele_face_pt->node_pt(nnode-1)->x(i);
37626  }
37627  local_vertex_nodes.insert(vertex_coord);
37628 
37629  // The initial and final node on the set
37630  Node *first_node_pt = ele_face_pt->node_pt(0);
37631  Node *last_node_pt = ele_face_pt->node_pt(nnode-1);
37632 
37633  // Mark the current face element as done
37634  face_element_done[ele_face_pt] = true;
37635 
37636  // -------------------------------------------------------
37637  // Find the global index in the mesh of the face element
37638  // and use it to get its associated target area
37639  // -------------------------------------------------------
37640  // Container to store the zeta value (used as index) and
37641  // the associated target area of the element
37642  Vector<double> zeta_target_area_values(2);
37643 
37644  // Use the minimum zeta value to sort the target areas
37645  // along the boundary
37646  zeta_target_area_values[0] =
37647  std::min(bound_left[0], bound_right[0]);
37648 
37649  // Get the index of the face element on the current boundary
37650  unsigned ef = face_element_index_on_boundary[ele_face_pt];
37651  // Get the "ef"-th element on the boundary
37652  FiniteElement *el_pt = this->boundary_element_pt(bound, ef);
37653 
37654 #ifdef PARANOID
37655  bool found_global_element_index = false;
37656 #endif
37657  for (unsigned eg = 0 ; eg < nele; eg++)
37658  {
37659  // Get the "eg-th" element
37660  FiniteElement *el_compare_pt = this->finite_element_pt(eg);
37661 
37662  // Compare with the element on the boundary, if equal then
37663  // store the target area
37664  if (el_pt == el_compare_pt)
37665  {
37666  zeta_target_area_values[1] = target_area[eg];
37667 #ifdef PARANOID
37668  found_global_element_index = true;
37669 #endif
37670  break; // break the for (e < nele) global element
37671  } // if element_pt == element_compare_pt
37672  } // for nele (on complete mesh)
37673 
37674 #ifdef PARANOID
37675  if (!found_global_element_index)
37676  {
37677  std::ostringstream error_message;
37678  error_message
37679  << "The global index for the ("<< ef <<")-th face element "
37680  << "on\nthe ("<< bound <<")-th boundary was not found!!!";
37681  throw OomphLibError(error_message.str(),
37682  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37683  OOMPH_EXCEPTION_LOCATION);
37684  }
37685 #endif
37686 
37687  // Add the target areas to the sorted set
37688  sorted_target_areas.insert(zeta_target_area_values);
37689  // ------------------------------------------------------------------
37690 
37691  // Continue iterating if a new face element has been added to the
37692  // list
37693  bool face_element_added = false;
37694 
37695  // While a new face element has been added to the set of sorted
37696  // face elements then re-iterate
37697  do
37698  {
37699  // Start from the next face elements since we have already
37700  // added the previous one as the initial face element (any
37701  // previous face element had to be added on previous
37702  // iterations)
37703  for (unsigned iiface=iface;iiface<nnon_halo_face_element;iiface++)
37704  {
37705  face_element_added = false;
37706  ele_face_pt = non_halo_face_element_pt[iiface];
37707  if (!face_element_done[ele_face_pt])
37708  {
37709  // Get each individual node to check if they are contiguous
37710  nnode = ele_face_pt->nnode();
37711  Node* left_node_pt = ele_face_pt->node_pt(0);
37712  Node* right_node_pt = ele_face_pt->node_pt(nnode-1);
37713 
37714  if (left_node_pt == first_node_pt)
37715  {
37716  first_node_pt = right_node_pt;
37717  face_element_added = true;
37718  }
37719  else if (left_node_pt == last_node_pt)
37720  {
37721  last_node_pt = right_node_pt;
37722  face_element_added = true;
37723  }
37724  else if (right_node_pt == first_node_pt)
37725  {
37726  first_node_pt = left_node_pt;
37727  face_element_added = true;
37728  }
37729  else if (right_node_pt == last_node_pt)
37730  {
37731  last_node_pt = left_node_pt;
37732  face_element_added = true;
37733  }
37734 
37735  if (face_element_added)
37736  {
37737  // Add the left-hand node to the set:
37738  // Boundary coordinate
37739  left_node_pt->get_coordinates_on_boundary(bound,bound_left);
37740  vertex_coord[0] = bound_left[0];
37741 
37742  // Actual coordinates
37743  for(unsigned i=0;i<2;i++)
37744  {
37745  vertex_coord[i+1] = left_node_pt->x(i);
37746  }
37747  local_vertex_nodes.insert(vertex_coord);
37748 
37749  // Add the right-hand nodes to the set:
37750  // Boundary coordinate
37751  right_node_pt->get_coordinates_on_boundary(bound,bound_right);
37752  vertex_coord[0] = bound_right[0];
37753 
37754  // Actual coordinates
37755  for(unsigned i=0;i<2;i++)
37756  {
37757  vertex_coord[i+1] = right_node_pt->x(i);
37758  }
37759  local_vertex_nodes.insert(vertex_coord);
37760 
37761  // Mark as done only if one of its nodes has been
37762  // added to the list
37763  face_element_done[ele_face_pt] = true;
37764  nsorted_face_elements++;
37765 
37766  // -----------------------------------------------------
37767  // Find the global index in the mesh of the face element
37768  // and use it to get its associated target area
37769  // -----------------------------------------------------
37770  // Use the minimum zeta value to sort the target areas
37771  // along the boundary
37772  zeta_target_area_values[0] =
37773  std::min(bound_left[0], bound_right[0]);
37774 
37775  // Get the "ef"-th element on the boundary
37776  ef = face_element_index_on_boundary[ele_face_pt];
37777  FiniteElement *lel_pt = this->boundary_element_pt(bound, ef);
37778 
37779 #ifdef PARANOID
37780  found_global_element_index = false;
37781 #endif
37782  for (unsigned eg = 0 ; eg < nele; eg++)
37783  {
37784  // Get the "eg-th" element
37785  FiniteElement *lel_compare_pt = this->finite_element_pt(eg);
37786 
37787  // Compare with the element on the boundary, if equal then
37788  // store the target area
37789  if (lel_pt == lel_compare_pt)
37790  {
37791  zeta_target_area_values[1] = target_area[eg];
37792 #ifdef PARANOID
37793  found_global_element_index = true;
37794 #endif
37795  break; // break the for (e < nele) global element
37796  } // if element_pt == element_compare_pt
37797  } // for nele (on complete mesh)
37798 
37799 #ifdef PARANOID
37800  if (!found_global_element_index)
37801  {
37802  std::ostringstream error_message;
37803  error_message
37804  << "The global index for the ("<< ef <<")-th face element "
37805  << "on\nthe ("<< bound <<")-th boundary was not found!!!";
37806  throw OomphLibError(error_message.str(),
37807  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37808  OOMPH_EXCEPTION_LOCATION);
37809  }
37810 #endif
37811 
37812  // Add the target areas to the sorted set
37813  sorted_target_areas.insert(zeta_target_area_values);
37814 
37815  break;
37816  }
37817 
37818  } // if (!edge_done[edge])
37819  } // for (iiedge < nedges)
37820  }while(face_element_added &&
37821  (nsorted_face_elements < nnon_halo_face_element));
37822 
37823  // -----------------------------------------------------------------
37824  // At this point we already have a sorted set of nodes and
37825  // can be used to peform the unrefinement and refinement procedures
37826  // -----------------------------------------------------------------
37827 
37828  // Get the number of nodes on the list
37829  const unsigned nlocal_nodes = local_vertex_nodes.size();
37830  // Change representation to vector for easy of handling ...
37831  local_tmp_vector_vertex_node.resize(nlocal_nodes);
37832 
37833  // Copy the vertices of the nodes
37834  unsigned counter = 0;
37835  std::set<Vector<double> >::iterator it_vertex;
37836  for (it_vertex = local_vertex_nodes.begin();
37837  it_vertex != local_vertex_nodes.end();
37838  it_vertex++)
37839  {
37840  local_tmp_vector_vertex_node[counter].resize(3);
37841  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
37842  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
37843  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
37844  counter++;
37845  }
37846 
37847  // ... same for the info. related with the target areas (turn
37848  // into vector)
37849  const unsigned ntarget_areas = sorted_target_areas.size();
37850  tmp_sorted_target_areas.resize(ntarget_areas);
37851  counter = 0;
37852  std::set<Vector<double> >::iterator it_area;
37853  for(it_area = sorted_target_areas.begin();
37854  it_area != sorted_target_areas.end();
37855  ++it_area)
37856  {
37857  tmp_sorted_target_areas[counter] = (*it_area)[1];
37858  ++counter;
37859  }
37860 
37861 #ifdef PARANOID
37862  if (nlocal_nodes > 0 && (ntarget_areas != nlocal_nodes - 1) )
37863  {
37864  std::ostringstream error_message;
37865  error_message
37866  << "The boundary (" << bound << ") was split during the "
37867  << "distribution process.\n"
37868  << "The problem is in the association of the target areas with the\n"
37869  << "elements that gave rise to the vertex coordinates.\n"
37870  << "The number of local nodes (" << nlocal_nodes
37871  << "), on the 'sub-polyline', is not\n"
37872  << "according with the number of target "
37873  << "areas ("<< ntarget_areas << ")\nfor that number of nodes.\n"
37874  << "The target areas number MUST be equal to the number of\n"
37875  << "local nodes minus one\n\n";
37876  throw OomphLibError(error_message.str(),
37877  OOMPH_CURRENT_FUNCTION,
37878  OOMPH_EXCEPTION_LOCATION);
37879  }
37880 #endif
37881 
37882  // -------------------------------------------------------------------
37883  // Update the vertices along the boundary using the target area
37884  // to define the distance among them
37885  // -------------------------------------------------------------------
37886 
37887  // Tolerance below which the middle point can be deleted
37888  // (ratio of deflection to element length)
37889  double unrefinement_tolerance=
37890  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
37891 
37892  // Apply unrefinement
37893  bool unrefinement_applied =
37894  unrefine_boundary_constrained_by_target_area(
37895  bound, chunk, local_tmp_vector_vertex_node,
37896  unrefinement_tolerance, tmp_sorted_target_areas);
37897 
37898  // Tolerance for refinement
37899  double refinement_tolerance=
37900  polygon_pt->polyline_pt(p)->refinement_tolerance();
37901 
37902  // Apply refinement
37903  bool refinement_applied =
37904  refine_boundary_constrained_by_target_area(
37905  mesh_geom_obj_pt, local_tmp_vector_vertex_node,
37906  refinement_tolerance, tmp_sorted_target_areas);
37907 
37908  // Clear the local containter to recover the nodes ordered using the
37909  // zeta value
37910  local_vertex_nodes.clear();
37911 
37912  // At the end of each unrefinement/refinement step store the new nodes
37913  // on the set that will give rise to the vertices of the new polyline
37914  // representation
37915  unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
37916  for (unsigned i = 0; i < nnew_nodes; i++)
37917  {
37918  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
37919  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
37920  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
37921  vertex_nodes.insert(vertex_coord); // Global container
37922  local_vertex_nodes.insert(vertex_coord);
37923  }
37924 
37925  // Update the flag to indicate whether an unrefinement or
37926  // refinement was applied
37927  update_was_performed = (unrefinement_applied || refinement_applied);
37928 
37929 #ifdef OOMPH_HAS_MPI
37930  if (this->is_mesh_distributed())
37931  {
37932  // Add the set of vertices for the boundary, this will help to
37933  // detect if we need to deal with sub-boundaries
37934  sub_vertex_nodes.push_back(local_vertex_nodes);
37935  // Increase the counter for sub-boundaries
37936  nsub_boundaries++;
37937  }
37938 #endif
37939 
37940  } // while(nsorted_face_elements < nnon_halo_face_element)
37941 
37942  // Now turn into vector for ease of handling...
37943  unsigned npoly_vertex = vertex_nodes.size();
37944  // This will store all the vertices whether the boundary was split
37945  // or not
37946  tmp_vector_vertex_node.resize(npoly_vertex);
37947  unsigned count = 0;
37948  for(std::set<Vector<double> >::iterator it = vertex_nodes.begin();
37949  it!=vertex_nodes.end(); ++it)
37950  {
37951  tmp_vector_vertex_node[count].resize(3);
37952  tmp_vector_vertex_node[count][0] = (*it)[0];
37953  tmp_vector_vertex_node[count][1] = (*it)[1];
37954  tmp_vector_vertex_node[count][2] = (*it)[2];
37955  ++count;
37956  }
37957 
37958 #ifdef OOMPH_HAS_MPI
37959  // --------- Stuff for the sub_boundaries ----- Begin section ---------
37960 #ifdef PARANOID
37961  unsigned nsub_boundaries_set = sub_vertex_nodes.size();
37962  if (nsub_boundaries_set != nsub_boundaries)
37963  {
37964  std::ostringstream error_message;
37965  error_message
37966  << "The number of found sub-boundaries and the number of counted\n"
37967  << "sub-boundaries are different:\n"
37968  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
37969  << "Number of counted sub-boundaries: ("<<nsub_boundaries<<")\n";
37970  throw OomphLibError(error_message.str(),
37971  OOMPH_CURRENT_FUNCTION,
37972  OOMPH_EXCEPTION_LOCATION);
37973  }
37974 #endif
37975 
37976  // Are there sub-boundaries (only appear in distributed meshes)
37977  if (this->is_mesh_distributed() && nsub_boundaries > 1)
37978  {
37979  // Mark the boundary as been splitted in the partition process
37980  this->Boundary_was_splitted[bound] = true;
37981  // Resize the vector to store the info. of sub-boundaries
37982  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
37983  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
37984  {
37985  // Turn info. into vector for ease of handling...
37986  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
37987  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
37988  unsigned subcount = 0;
37989  std::set<Vector<double> >::iterator subit;
37990  for(subit = sub_vertex_nodes[isub].begin();
37991  subit != sub_vertex_nodes[isub].end(); ++subit)
37992  {
37993  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
37994  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
37995  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
37996  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
37997  ++subcount;
37998  }
37999  }
38000  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38001  // --------- Stuff for the sub_boundaries ----- End section ------------
38002 #endif // OOMPH_HAS_MPI
38003 
38004  // For further processing the three-dimensional vector has to be
38005  // reduced to a two-dimensional vector
38006  unsigned n_vertex=tmp_vector_vertex_node.size();
38007 
38008  // Resize the vector for vectices
38009  vector_vertex_node.resize(n_vertex);
38010  for(unsigned i=0;i<n_vertex;i++)
38011  {
38012  vector_vertex_node[i].resize(2);
38013  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
38014  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
38015  }
38016 
38017 #ifdef OOMPH_HAS_MPI
38018  // --------- Stuff for the sub_boundaries ----- Begin section ----------
38019  // Verify if need to deal with sub_boundaries
38020  if (this->is_mesh_distributed() && nsub_boundaries > 1)
38021  {
38022  // For further processing the three-dimensional vector
38023  // has to be reduced to a two-dimensional vector
38024  // Resize the vector to store the info. of sub-boundaries
38025  sub_vector_vertex_node.resize(nsub_boundaries);
38026  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
38027  {
38028  const unsigned subn_vertex =
38029  sub_tmp_vector_vertex_node[isub].size();
38030  // Resize the vector for vectices
38031  sub_vector_vertex_node[isub].resize(subn_vertex);
38032  for(unsigned i=0;i<subn_vertex;i++)
38033  {
38034  sub_vector_vertex_node[isub][i].resize(2);
38035  sub_vector_vertex_node[isub][i][0]=
38036  sub_tmp_vector_vertex_node[isub][i][1];
38037  sub_vector_vertex_node[isub][i][1]=
38038  sub_tmp_vector_vertex_node[isub][i][2];
38039  }
38040  }
38041  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38042 
38043  // We already have the info. for the sub-boundaries (if necessary)
38044  // and then we can create the sub-boundaries representations to
38045  // ease the generation of the mesh by Triangle
38046 
38047  // --------- Stuff for the sub_boundaries ----- End section ------------
38048  #endif // OOMPH_HAS_MPI
38049 
38050  // --------------------------------------------------------------------
38051  // Check for contiguousness
38052  // --------------------------------------------------------------------
38053 #ifdef OOMPH_HAS_MPI
38054  // Only perform this checking if the mesh is not distributed. When
38055  // the mesh is distributed the polylines continuity is addressed
38056  // by the sort_polylines_helper() method
38057  if (!this->is_mesh_distributed())
38058 #endif
38059  {
38060  if ( p > 0 )
38061  {
38062  //Final end point of previous line
38063  Vector<double> final_vertex_of_previous_segment;
38064  unsigned n_prev_vertex =
38065  polygon_pt->curve_section_pt(p-1)->nvertex();
38066  final_vertex_of_previous_segment =
38067  polygon_pt->polyline_pt(p-1)->
38068  vertex_coordinate(n_prev_vertex-1);
38069 
38070  unsigned prev_seg_boundary_id =
38071  polygon_pt->curve_section_pt(p-1)->boundary_id();
38072 
38073  //Find the error between the final vertex of the previous
38074  //line and the first vertex of the current line
38075  double error = 0.0;
38076  for(unsigned i=0;i<2;i++)
38077  {
38078  const double dist =
38079  final_vertex_of_previous_segment[i] -
38080  (*vector_vertex_node.begin())[i];
38081  error += dist*dist;
38082  }
38083  error = sqrt(error);
38084 
38085  //If the error is bigger than the tolerance then
38086  //we probably need to reverse, but better check
38088  {
38089  //Find the error between the final vertex of the previous
38090  //line and the last vertex of the current line
38091  double rev_error = 0.0;
38092  for(unsigned i=0;i<2;i++)
38093  {
38094  const double dist =
38095  final_vertex_of_previous_segment[i] -
38096  (*--vector_vertex_node.end())[i];
38097  rev_error += dist*dist;
38098  }
38099  rev_error = sqrt(rev_error);
38100 
38101  if(rev_error >
38103  {
38104  // It could be possible that the first segment be reversed
38105  // and we did not notice it because this check does not
38106  // apply for the first segment. We can verify if the first
38107  // segment is reversed by using the vertex number 1
38108  if (p == 1)
38109  {
38110  //Initial end point of previous line
38111  Vector<double> initial_vertex_of_previous_segment;
38112 
38113  initial_vertex_of_previous_segment =
38114  polygon_pt->polyline_pt(p-1)->
38115  vertex_coordinate(0);
38116 
38117  unsigned prev_seg_boundary_id =
38118  polygon_pt->curve_section_pt(p-1)->boundary_id();
38119 
38120  //Find the error between the initial vertex of the previous
38121  //line and the first vertex of the current line
38122  double error = 0.0;
38123  for(unsigned i=0;i<2;i++)
38124  {
38125  const double dist =
38126  initial_vertex_of_previous_segment[i] -
38127  (*vector_vertex_node.begin())[i];
38128  error += dist*dist;
38129  }
38130  error = sqrt(error); // Reversed only the previous one
38131 
38132  //If the error is bigger than the tolerance then
38133  //we probably need to reverse, but better check
38135  {
38136  //Find the error between the final vertex of the previous
38137  //line and the last vertex of the current line
38138  double rev_error = 0.0;
38139  for(unsigned i=0;i<2;i++)
38140  {
38141  const double dist =
38142  initial_vertex_of_previous_segment[i] -
38143  (*--vector_vertex_node.end())[i];
38144  rev_error += dist*dist;
38145  }
38146  rev_error = sqrt(rev_error); // Reversed both the current one and
38147  // the previous one
38148 
38149  if (rev_error >
38151  {
38152  std::ostringstream error_stream;
38153  error_stream
38154  <<"The distance between the first node of the current\n"
38155  <<"line segment (boundary "<<bound<<") and either end of "
38156  << "the previous line segment\n"
38157  << "(boundary "<<prev_seg_boundary_id<<") is bigger than "
38158  << "the desired tolerance "
38160  << ".\n"
38161  << "This suggests that the polylines defining the "
38162  << "polygonal\n"
38163  << "representation are not properly ordered.\n"
38164  << "Fail on last vertex of polyline: ("
38165  << prev_seg_boundary_id << ") and\n"
38166  << "first vertex of polyline (" << bound << ").\n"
38167  << "This should have failed when first trying to "
38168  << "construct the\npolygon.\n";
38169  throw OomphLibError(error_stream.str(),
38170  OOMPH_CURRENT_FUNCTION,
38171  OOMPH_EXCEPTION_LOCATION);
38172  }
38173  else
38174  {
38175  // Reverse both
38176  // Reverse the current vector to line up with the
38177  // previous one
38178  std::reverse(vector_vertex_node.begin(),
38179  vector_vertex_node.end());
38180 
38181  polygon_pt->polyline_pt(p-1)->reverse();
38182  }
38183  }
38184  else
38185  {
38186  // Reverse the previous one
38187  polygon_pt->polyline_pt(p-1)->reverse();
38188  }
38189 
38190  } // if p == 1
38191  else
38192  {
38193  std::ostringstream error_stream;
38194  error_stream
38195  <<"The distance between the first node of the current\n"
38196  <<"line segment (boundary " << bound << ") and either end of "
38197  <<"the previous line segment\n"
38198  <<"(boundary "<<prev_seg_boundary_id<<") is bigger than the "
38199  <<"desired tolerance " <<
38201  <<"This suggests that the polylines defining the polygonal\n"
38202  <<"representation are not properly ordered.\n"
38203  << "Fail on last vertex of polyline: ("<<prev_seg_boundary_id
38204  << ") and\nfirst vertex of polyline ("<<bound << ").\n"
38205  << "This should have failed when first trying to construct"
38206  << " the polygon.\n";
38207  throw OomphLibError(error_stream.str(),
38208  OOMPH_CURRENT_FUNCTION,
38209  OOMPH_EXCEPTION_LOCATION);
38210  }
38211  }
38212  else
38213  {
38214  //Reverse the current vector to line up with the previous one
38215  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
38216  }
38217  } // error
38218 
38219  } // if ( p > 0 )
38220 
38221  } // if (!this->is_mesh_distributed())
38222 
38223  // --------------------------------------------------------------------
38224  // Update the polylines representation
38225  // --------------------------------------------------------------------
38226 
38227  // Always update the polylines representation, in a distributed
38228  // mesh it is necessary to update the polyline representation since
38229  // it may no longer have vertices (the boundary may not be part of
38230  // the domain in the current processor)
38231 
38232  // The new nunber of vertices
38233  n_vertex = vector_vertex_node.size();
38234 
38235  // Now update the polyline according to the new vertices
38236  TriangleMeshPolyLine *tmp_polyline_pt =
38237  new TriangleMeshPolyLine(vector_vertex_node,bound);
38238 
38239  // Create a temporal "curve section" version of the recently
38240  // created polyline
38241  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
38242 
38243  // Tolerance below which the middle point can be deleted (ratio of
38244  // deflection to element length)
38245  double unrefinement_tolerance=
38246  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
38247 
38248  // Tolerance to add points
38249  double refinement_tolerance=
38250  polygon_pt->polyline_pt(p)->refinement_tolerance();
38251 
38252  // Establish refinement and unrefinement tolerance
38253  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
38254  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
38255 
38256  // Establish the maximum length constraint
38257  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
38258  tmp_polyline_pt->set_maximum_length(maximum_length);
38259 
38260 #ifdef OOMPH_HAS_MPI
38261  // If the mesh is distributed check that the polyline still has
38262  // vertices
38263  if (this->is_mesh_distributed())
38264  {
38265  if (n_vertex >= 2)
38266  {
38267  // Pass the connection information from the old polyline to the
38268  // new one
38269  this->copy_connection_information(polygon_pt->polyline_pt(p),
38270  tmp_curve_section_pt);
38271  } // if (n_vertex >= 2)
38272  } // if (this->is_mesh_distributed())
38273  else
38274 #endif
38275  {
38276  // Pass the connection information from the old polyline to the
38277  // new one
38278  this->copy_connection_information(polygon_pt->polyline_pt(p),
38279  tmp_curve_section_pt);
38280  }
38281 
38282  // Now update the polyline according to the new vertices but first
38283  // check if the object is allowed to delete the representation or
38284  // if it should be done by other object
38285  bool delete_it_on_destructor = false;
38286 
38287  std::set<TriangleMeshCurveSection*>::iterator it =
38288  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
38289 
38290  if (it!=this->Free_curve_section_pt.end())
38291  {
38292  this->Free_curve_section_pt.erase(it);
38293  delete polygon_pt->curve_section_pt(p);
38294  delete_it_on_destructor = true;
38295  }
38296 
38297  // -------------------------------------------------------
38298  // Copying the new representation
38299  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
38300 
38301  // Update the Boundary - Polyline map
38302  this->Boundary_curve_section_pt[bound] = polygon_pt->curve_section_pt(p);
38303 
38304  if (delete_it_on_destructor)
38305  {
38306  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
38307  }
38308 
38309 #ifdef OOMPH_HAS_MPI
38310  // --------- Stuff for the sub_boundaries ----- Begin section --------
38311  // Verify if need to deal with sub_boundaries
38312  if (this->is_mesh_distributed() && nsub_boundaries > 1)
38313  {
38314  // Create temporary representations for the boundaries, only to
38315  // create the mesh when calling Triangle
38316 
38317  // Clear all previous stored data
38318  this->Boundary_subpolylines[bound].clear();
38319 
38320  // Create storage for the sub-boundaries
38321  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
38322  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
38323  {
38324  // Update the polyline according to the sub set of vertices,
38325  TriangleMeshPolyLine *sub_tmp_polyline_pt =
38326  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
38327 
38328  // Add the sub-polyline to the container to represent the
38329  // boundary in parts
38330  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
38331 
38332  // No need to send the unrefinement/refinement and maximum
38333  // length constraints since these are only temporary
38334  // representations. These polylines can be deleted once the new
38335  // polygons that represent the distributed domain have been
38336  // created
38337 
38338  } // for (isub < nsub_boundaries)
38339 
38340  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38341  // --------- Stuff for the sub_boundaries ----- End section ---------
38342  #endif // OOMPH_HAS_MPI
38343 
38344  // Delete the allocated memory for the geometric object that
38345  // represents the boundary
38346  delete mesh_geom_obj_pt;
38347 
38348  } // for (p < n_polyline)
38349 
38350  // Cleanup the face mesh
38351  for(unsigned p=0;p<n_polyline;p++)
38352  {
38353  face_mesh_pt[p]->flush_node_storage();
38354  delete face_mesh_pt[p];
38355  }
38356 
38357  return update_was_performed;
38358 
38359 }
38360 
38361 //======================================================================
38362 /// \short Updates the open curve but using the elements area instead
38363 /// of the default refinement and unrefinement methods
38364 //======================================================================
38365 template <class ELEMENT>
38368  const Vector<double> &target_area)
38369 {
38370  // Verify if there was a change on the open curve representation
38371  unsigned update_was_performed = false;
38372 
38373  const unsigned nele = this->nelement();
38374 
38375  // - Get the vertices along the boundaries and for each element identify
38376  // its associated target error.
38377  // - Get face mesh representation of each polyline.
38378  // - Get the vertices with the help of face elements.
38379  // - Find the global index in the mesh of the face element
38380  // and use it to get its associated target area.
38381 
38382  // Get the face mesh representation
38383  Vector<Mesh*> face_mesh_pt;
38384  get_face_mesh_representation(open_curve_pt,face_mesh_pt);
38385 
38386  // Create vertices of the polylines by using the vertices of the
38387  // FaceElements
38388  Vector<double> vertex_coord(3); // zeta,x,y
38389  Vector<double> bound_left(1);
38390  Vector<double> bound_right(1);
38391 
38392  const unsigned ncurve_section = open_curve_pt->ncurve_section();
38393 
38394  // Go for each curve section
38395  for(unsigned cs = 0; cs < ncurve_section; cs++)
38396  {
38397  // Get the MeshAsGeomObject representation just once per polyline,
38398  // this object is only used by the
38399  // refine_boundary_constrained_by_target_area() method. We get it
38400  // here to ensure that all processors (in a distributed context)
38401  // get this representation just once, and because an AllToAll MPI
38402  // communication is used in this calling
38403  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt[cs]);
38404 
38405  //Get the boundary id
38406  const unsigned bound =
38407  open_curve_pt->curve_section_pt(cs)->boundary_id();
38408 
38409  // Get the chunk number
38410  const unsigned chunk =
38411  open_curve_pt->curve_section_pt(cs)->boundary_chunk();
38412 
38413  /// Use a vector of vector for vertices and target areas to deal
38414  /// with the cases when the boundaries are split by the
38415  /// distribution process. Internal boundaries may be completely or
38416  /// partially overlapped by shared boundaries
38417 
38418  // Loop over the face elements and add their vertices (they are
38419  // automatically sorted because of the set)
38420  const unsigned nface_element = face_mesh_pt[cs]->nelement();
38421 
38422  // Store the non halo elements and the element at the other side of
38423  // the boundary (whatever it be halo or not), the first will be the
38424  // ones from which we will get the vertices (in even position)
38425  Vector<FiniteElement*> non_halo_doubled_face_element_pt;
38426 
38427  // Map to store the index of the face element on a boundary
38428  std::map<FiniteElement*,unsigned> face_element_index_on_boundary;
38429 
38430  // Map to know the already sorted face elements
38431  std::map<FiniteElement*,bool> face_element_done;
38432 
38433  for(unsigned ef = 0; ef < nface_element; ++ef)
38434  {
38435  FiniteElement* ele_face_pt = face_mesh_pt[cs]->finite_element_pt(ef);
38436 
38437  // Skip the halo elements (not used as base elements, only
38438  // include those elements whose element at the other side of the
38439  // boundary is non halo)
38440 #ifdef OOMPH_HAS_MPI
38441  if (this->is_mesh_distributed())
38442  {
38443  // Only work with non-halo elements
38444  if (ele_face_pt->is_halo()) {continue;}
38445  }
38446 #endif
38447 
38448  // Check if not already done
38449  if (!face_element_done[ele_face_pt])
38450  {
38451  // Add the element and look for the element at the other side
38452  // of the boundary to add it immediately after the new added
38453  // element
38454  non_halo_doubled_face_element_pt.push_back(ele_face_pt);
38455  // Create the map of the face element with the index
38456  face_element_index_on_boundary[ele_face_pt] = ef;
38457  // Mark the current element as done
38458  face_element_done[ele_face_pt] = true;
38459  // Get the number of nodes
38460  const unsigned nnodes = ele_face_pt->nnode();
38461  // Get the left and right node to look for the elements at the
38462  // other side of the boundary
38463  Node* left_node_pt = ele_face_pt->node_pt(0);
38464  Node* right_node_pt = ele_face_pt->node_pt(nnodes-1);
38465 #ifdef PARANOID
38466  // Flag to know if the element at the other side of the
38467  // boundary was found
38468  bool found_other_side_face_ele = false;
38469 #endif
38470  for (unsigned iface = 0; iface < nface_element; iface++)
38471  {
38472  // Get the candidate face element
38473  FiniteElement *cele_face_pt =
38474  face_mesh_pt[cs]->finite_element_pt(iface);
38475  // Check if not already done
38476  if (!face_element_done[cele_face_pt])
38477  {
38478  Node* cleft_node_pt = cele_face_pt->node_pt(0);
38479  Node* cright_node_pt = cele_face_pt->node_pt(nnodes-1);
38480  // Check if the nodes are the same
38481  if ((left_node_pt == cleft_node_pt &&
38482  right_node_pt == cright_node_pt) ||
38483  (left_node_pt == cright_node_pt &&
38484  right_node_pt == cleft_node_pt))
38485  {
38486  // Add the element to the storage
38487  non_halo_doubled_face_element_pt.push_back(cele_face_pt);
38488  // ... and mark the element as done
38489  face_element_done[cele_face_pt] = true;
38490  // Create the map of the face element with the index
38491  face_element_index_on_boundary[cele_face_pt] = iface;
38492 #ifdef PARANOID
38493  // Set the flag of found other side face element
38494  found_other_side_face_ele = true;
38495 #endif
38496  break;
38497  }
38498  }
38499  } // (iface < nface_element)
38500 
38501 #ifdef PARANOID
38502  if (!found_other_side_face_ele)
38503  {
38504  std::ostringstream error_message;
38505  error_message
38506  << "The face element at the other side of the boundary ("
38507  << bound << ") was not found!!\n"
38508  << "These are the nodes of the face element:\n"
38509  << "("<<left_node_pt->x(0)<<", "<<left_node_pt->x(1)<<") "
38510  << "and ("<<right_node_pt->x(0)<<","<<right_node_pt->x(1)<<")\n\n";
38511  throw OomphLibError(error_message.str(),
38512  "RefineableTriangleMesh::update_open_curve_using_elements_area()",
38513  OOMPH_EXCEPTION_LOCATION);
38514  }
38515 #endif
38516  } // if (!face_ele_done[ele_face_pt])
38517 
38518  } // (ef < nface_element)
38519 
38520  // Clear the map of the already done face elements
38521  // This will be used to help sorting the face elements
38522  face_element_done.clear();
38523 
38524  // Set of coordinates that are on the boundary
38525  // The entries are sorted on first entry in vector which stores
38526  // the boundary coordinate so the vertices come out in order!
38527  std::set<Vector<double> > vertex_nodes;
38528 
38529  // Vector to store the vertices, transfer the sorted vertices from the
38530  // set to this vector, --- including the z-value ---
38531  Vector<Vector<double> > tmp_vector_vertex_node;
38532 
38533  // Vector to store the coordinates of the polylines, same as the
38534  // tmp_vector_vertex_node vector (after adding more nodes) but
38535  // --- without the z-value ---, used to re-generate the polylines
38536  Vector<Vector<double> > vector_vertex_node;
38537 
38538 #ifdef OOMPH_HAS_MPI
38539  // Indicates if the set of vertices give rise to a internal
38540  // boundary that will be used as shared boundary or as normal
38541  // internal boundary -- Only used to deal with internal boundaries
38542  // in a distributed scheme
38543  std::vector<bool> internal_to_shared_boundary;
38544 
38545  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
38546  // Set of coordinates that are on the boundary (splitted boundary version)
38547  // The first vector is used to allocate the points for each sub-boundary
38548  // Set entries are ordered on first entry in vector which stores
38549  // the boundary coordinate so the vertices come out in order!
38550  Vector<std::set<Vector<double> > > sub_vertex_nodes;
38551 
38552  // Vector to store the vertices, transfer the sorted vertices from the
38553  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
38554  Vector<Vector<Vector<double> > > sub_tmp_vector_vertex_node;
38555 
38556  // Vector to store the coordinates of the polylines that will represent
38557  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
38558  // but --- without the z-value ---, used to generate the sub-polylines
38559  Vector<Vector<Vector<double> > > sub_vector_vertex_node;
38560 
38561  // --------- Stuff to deal with splitted boundaries ----------- End ------
38562 
38563 #endif // #ifdef OOMPH_HAS_MPI
38564 
38565  // Sort the face element, those that have both elements (one at
38566  // each side of the boundary) marked as nonhalo, and those with one
38567  // nonhalo an the other as halo
38568 
38569  // Number of done face elements
38570  unsigned nsorted_face_elements = 0;
38571 
38572 #ifdef OOMPH_HAS_MPI
38573  // Counter for sub_boundaries
38574  unsigned nsub_boundaries = 0;
38575 #endif // #ifdef OOMPH_HAS_MPI
38576 
38577  // Total number of non halo double face element
38578  const unsigned nnon_halo_doubled_face_ele =
38579  non_halo_doubled_face_element_pt.size();
38580 
38581  // Continue until all the face elements have been sorted
38582  // This while is to deal with the cases of splitted boundaries
38583  while(nsorted_face_elements < nnon_halo_doubled_face_ele)
38584  {
38585  // Get and initial face element
38586  FiniteElement* ele_face_pt = 0;
38587  FiniteElement* repeated_ele_face_pt = 0;
38588 #ifdef PARANOID
38589  bool found_initial_face_element = false;
38590 #endif
38591 
38592  // Flag to know if we are working with a face element which the
38593  // face element at the other side of the boundary is also non
38594  // halo
38595  bool both_root_face_elements_are_nonhalo = false;
38596 
38597  unsigned iface = 0;
38598  for (iface = 0; iface < nnon_halo_doubled_face_ele; iface+=2)
38599  {
38600  ele_face_pt = non_halo_doubled_face_element_pt[iface];
38601  // If not done then take it as initial face element
38602  if (!face_element_done[ele_face_pt])
38603  {
38604  // Mark it as done
38605  face_element_done[ele_face_pt] = true;
38606  // Get the other side boundary face element
38607  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iface+1];
38608  // ... also mark as done the repeated face element
38609  face_element_done[repeated_ele_face_pt] = true;
38610 
38611 #ifdef OOMPH_HAS_MPI
38612  if (!repeated_ele_face_pt->is_halo())
38613  {both_root_face_elements_are_nonhalo = true;}
38614 #endif // #ifdef OOMPH_HAS_MPI
38615 
38616  // Plus two because internal boundaries have
38617  // two face elements per each edge
38618  nsorted_face_elements+=2;
38619  iface+=2;
38620 #ifdef PARANOID
38621  // And set the flag to true
38622  found_initial_face_element = true;
38623 #endif
38624  break;
38625  }
38626  }
38627 
38628 #ifdef PARANOID
38629  if (!found_initial_face_element)
38630  {
38631  std::ostringstream error_message;
38632  error_message
38633  <<"Could not find an initial face element for the current segment\n";
38634  throw OomphLibError(error_message.str(),
38635  OOMPH_CURRENT_FUNCTION,
38636  OOMPH_EXCEPTION_LOCATION);
38637  }
38638 #endif
38639 
38640  // Local set of coordinates that are on the boundary Set entries
38641  // are ordered on first entry in vector which stores the boundary
38642  // coordinate so the vertices come out in order
38643  std::set<Vector<double> > local_vertex_nodes;
38644 
38645  // Vector to store the vertices, transfer the sorted vertices from the
38646  // set (local) to this vector (local), --- including the z-value ---
38647  Vector<Vector<double> > local_tmp_vector_vertex_node;
38648 
38649  // Vector to store the target areas, uses the same approach as the
38650  // set for the local_vertex_nodes, ordered on first entry
38651  std::set<Vector<double> > sorted_target_areas;
38652 
38653  // Vector to store the target areas, used to transfer the sorted target
38654  // areas from "sorted_target_areas" set
38655  Vector<double> tmp_sorted_target_areas;
38656 
38657  // ------------------------------------------------------------------
38658  // Add the vertices of the initial face element to the set of local
38659  // sorted vertices
38660  // ------------------------------------------------------------------
38661  const unsigned nnode = ele_face_pt->nnode();
38662  // Add the left-hand node to the set:
38663  // Boundary coordinate
38664  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
38665  vertex_coord[0] = bound_left[0];
38666 
38667  // Actual coordinates
38668  for(unsigned i=0;i<2;i++)
38669  {
38670  vertex_coord[i+1] = ele_face_pt->node_pt(0)->x(i);
38671  }
38672  local_vertex_nodes.insert(vertex_coord);
38673 
38674  // Add the right-hand node to the set:
38675  // Boundary coordinate
38676  ele_face_pt->node_pt(nnode-1)->get_coordinates_on_boundary(bound,
38677  bound_right);
38678  vertex_coord[0] = bound_right[0];
38679 
38680  // Actual coordinates
38681  for(unsigned i=0;i<2;i++)
38682  {
38683  vertex_coord[i+1] = ele_face_pt->node_pt(nnode-1)->x(i);
38684  }
38685  local_vertex_nodes.insert(vertex_coord);
38686 
38687  // The initial and final node on the set
38688  Node *first_node_pt = ele_face_pt->node_pt(0);
38689  Node *last_node_pt = ele_face_pt->node_pt(nnode-1);
38690 
38691  // -----------------------------------------------------
38692  // Find the global index in the mesh of the face element
38693  // and use it to get its associated target area
38694  // -----------------------------------------------------
38695  // Container to store the zeta value (used as index) and
38696  // the associated target area of the element
38697  Vector<double> zeta_target_area_values(2);
38698 
38699  // Use the minimum zeta value to sort the target areas
38700  // along the boundary
38701  zeta_target_area_values[0] = std::min(bound_left[0], bound_right[0]);
38702 
38703  // Get the index of the face element on the current boundary
38704  const unsigned ef = face_element_index_on_boundary[ele_face_pt];
38705  // Get the "ef"-th element on the boundary
38706  FiniteElement *el_pt = this->boundary_element_pt(bound, ef);
38707  double target_area_face_element = 0.0;
38708 
38709 #ifdef PARANOID
38710  bool found_global_element_index = false;
38711 #endif
38712  for (unsigned eg = 0 ; eg < nele; eg++)
38713  {
38714  // Get the "eg-th" element
38715  FiniteElement *el_compare_pt = this->finite_element_pt(eg);
38716 
38717  // Compare with the element on the boundary, if equal then
38718  // store the target area
38719  if (el_pt == el_compare_pt)
38720  {
38721  target_area_face_element = target_area[eg];
38722 #ifdef PARANOID
38723  found_global_element_index = true;
38724 #endif
38725  break; // break the for (eg < nele) global element
38726  } // if el_pt == el_compare_pt
38727  } // for nele (on complete mesh)
38728 
38729 #ifdef PARANOID
38730  if (!found_global_element_index)
38731  {
38732  std::ostringstream error_message;
38733  error_message
38734  << "The global index for the ("<< ef <<")-th face element "
38735  << "on\nthe ("<< bound <<")-th boundary was not found!!!";
38736  throw OomphLibError(error_message.str(),
38737  OOMPH_CURRENT_FUNCTION,
38738  OOMPH_EXCEPTION_LOCATION);
38739  }
38740 #endif
38741 
38742  // Get the index of the repeated face element on the current boundary
38743  const unsigned ref = face_element_index_on_boundary[repeated_ele_face_pt];
38744  FiniteElement *rel_pt = this->boundary_element_pt(bound, ref);
38745  double target_area_repeated_face_element = 0.0;
38746 
38747 #ifdef PARANOID
38748  bool found_global_repeated_element_index = false;
38749 #endif
38750  for (unsigned eg = 0 ; eg < nele; eg++)
38751  {
38752  // Get the "eg-th" element
38753  FiniteElement *el_compare_pt = this->finite_element_pt(eg);
38754 
38755  // Compare with the element on the boundary, if equal then
38756  // store the target area
38757  if (rel_pt == el_compare_pt)
38758  {
38759  target_area_repeated_face_element = target_area[eg];
38760 #ifdef PARANOID
38761  found_global_repeated_element_index = true;
38762 #endif
38763  break; // break the for (eg < nele) global element
38764  } // if rel_pt == el_compare_pt
38765  } // for nele (on complete mesh)
38766 
38767 #ifdef PARANOID
38768  if (!found_global_repeated_element_index)
38769  {
38770  std::ostringstream error_message;
38771  error_message
38772  << "The global index for the ("<< ref <<")-th face element "
38773  << "on\nthe ("<< bound <<")-th boundary was not found (repeated "
38774  << "face element)!!!";
38775  throw OomphLibError(error_message.str(),
38776  OOMPH_CURRENT_FUNCTION,
38777  OOMPH_EXCEPTION_LOCATION);
38778  }
38779 #endif
38780 
38781  // Choose the minimum target area from both elements, one at each side
38782  // of the edge on the boundary
38783  zeta_target_area_values[1]=std::min(target_area_face_element,
38784  target_area_repeated_face_element);
38785 
38786  // Add the target areas to the sorted set
38787  sorted_target_areas.insert(zeta_target_area_values);
38788  // ------------------------------------------------------------------
38789 
38790  // Continue iterating if a new face element has been added to the
38791  // list
38792  bool face_element_added = false;
38793 
38794  // While a new face element has been added to the set of sorted
38795  // face elements then re-iterate
38796  do
38797  {
38798  // Start from the next face elements since we have already
38799  // added the previous one as the initial face element (any
38800  // previous face element had to be added on previous
38801  // iterations)
38802  for (unsigned iiface=iface;
38803  iiface<nnon_halo_doubled_face_ele;iiface+=2)
38804  {
38805  face_element_added = false;
38806  ele_face_pt = non_halo_doubled_face_element_pt[iiface];
38807 
38808  // Check that the face element with which we are working has
38809  // the same conditions as the root face element (both faces
38810  // are nonhalo or one face is halo and the other nonhalo)
38811 
38812  // Get the face element at the other side of the boundary
38813  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface+1];
38814  bool both_face_elements_are_nonhalo = false;
38815 
38816 #ifdef OOMPH_HAS_MPI
38817  if (!repeated_ele_face_pt->is_halo())
38818  {both_face_elements_are_nonhalo = true;}
38819 #endif // #ifdef OOMPH_HAS_MPI
38820 
38821  if (!face_element_done[ele_face_pt] &&
38822  (both_face_elements_are_nonhalo ==
38823  both_root_face_elements_are_nonhalo))
38824  {
38825  // Get each individual node to check if they are contiguous
38826  const unsigned nlnode = ele_face_pt->nnode();
38827  Node* left_node_pt = ele_face_pt->node_pt(0);
38828  Node* right_node_pt = ele_face_pt->node_pt(nlnode-1);
38829 
38830  if (left_node_pt == first_node_pt)
38831  {
38832  first_node_pt = right_node_pt;
38833  face_element_added = true;
38834  }
38835  else if (left_node_pt == last_node_pt)
38836  {
38837  last_node_pt = right_node_pt;
38838  face_element_added = true;
38839  }
38840  else if (right_node_pt == first_node_pt)
38841  {
38842  first_node_pt = left_node_pt;
38843  face_element_added = true;
38844  }
38845  else if (right_node_pt == last_node_pt)
38846  {
38847  last_node_pt = left_node_pt;
38848  face_element_added = true;
38849  }
38850 
38851  if (face_element_added)
38852  {
38853  // Add the left-hand node to the set:
38854  // Boundary coordinate
38855  left_node_pt->get_coordinates_on_boundary(bound,bound_left);
38856  vertex_coord[0] = bound_left[0];
38857 
38858  // Actual coordinates
38859  for(unsigned i=0;i<2;i++)
38860  {
38861  vertex_coord[i+1] = left_node_pt->x(i);
38862  }
38863  local_vertex_nodes.insert(vertex_coord);
38864 
38865  // Add the right-hand nodes to the set:
38866  // Boundary coordinate
38867  right_node_pt->get_coordinates_on_boundary(bound,bound_right);
38868  vertex_coord[0] = bound_right[0];
38869 
38870  // Actual coordinates
38871  for(unsigned i=0;i<2;i++)
38872  {
38873  vertex_coord[i+1] = right_node_pt->x(i);
38874  }
38875  local_vertex_nodes.insert(vertex_coord);
38876 
38877  // Mark as done only if one of its nodes has been
38878  // added to the list
38879  face_element_done[ele_face_pt] = true;
38880  // .. also mark as done the face element at the othe side of
38881  // the boundary
38882  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface+1];
38883  face_element_done[repeated_ele_face_pt] = true;
38884  // ... and increase the number of sorted face elements
38885  nsorted_face_elements+=2;
38886 
38887  // -----------------------------------------------------
38888  // Find the global index in the mesh of the face element
38889  // and use it to get its associated target area
38890  // -----------------------------------------------------
38891  // Use the minimum zeta value to sort the target areas
38892  // along the boundary
38893  zeta_target_area_values[0] =
38894  std::min(bound_left[0], bound_right[0]);
38895 
38896  // Get the "ef"-th element on the boundary
38897  const unsigned lef = face_element_index_on_boundary[ele_face_pt];
38898  FiniteElement *lel_pt = this->boundary_element_pt(bound, lef);
38899 
38900 #ifdef PARANOID
38901  found_global_element_index = false;
38902 #endif
38903  for (unsigned eg = 0 ; eg < nele; eg++)
38904  {
38905  // Get the "eg-th" element
38906  FiniteElement *lel_compare_pt = this->finite_element_pt(eg);
38907 
38908  // Compare with the element on the boundary, if equal then
38909  // store the target area
38910  if (lel_pt == lel_compare_pt)
38911  {
38912  target_area_face_element = target_area[eg];
38913 #ifdef PARANOID
38914  found_global_element_index = true;
38915 #endif
38916  break; // break the for (eg < nele) global element
38917  } // if lel_pt == lel_compare_pt
38918  } // for nele (on complete mesh)
38919 
38920 #ifdef PARANOID
38921  if (!found_global_element_index)
38922  {
38923  std::ostringstream error_message;
38924  error_message
38925  << "The global index for the ("<< lef <<")-th face element "
38926  << "on\nthe ("<< bound <<")-th boundary was not found!!!";
38927  throw OomphLibError(error_message.str(),
38928  OOMPH_CURRENT_FUNCTION,
38929  OOMPH_EXCEPTION_LOCATION);
38930  }
38931 #endif
38932 
38933  // Get the index of the repeated face element on the boundary
38934  const unsigned rlef =
38935  face_element_index_on_boundary[repeated_ele_face_pt];
38936  FiniteElement *rlel_pt = this->boundary_element_pt(bound, rlef);
38937 
38938 #ifdef PARANOID
38939  found_global_repeated_element_index = false;
38940 #endif
38941  for (unsigned eg = 0 ; eg < nele; eg++)
38942  {
38943  // Get the "eg-th" element
38944  FiniteElement *lel_compare_pt = this->finite_element_pt(eg);
38945 
38946  // Compare with the element on the boundary, if equal then
38947  // store the target area
38948  if (rlel_pt == lel_compare_pt)
38949  {
38950  target_area_repeated_face_element = target_area[eg];
38951 #ifdef PARANOID
38952  found_global_repeated_element_index = true;
38953 #endif
38954  break; // break the for (eg < nele) global element
38955  } // if rlel_pt == el_compare_pt
38956  } // for nele (on complete mesh)
38957 
38958 #ifdef PARANOID
38959  if (!found_global_repeated_element_index)
38960  {
38961  std::ostringstream error_message;
38962  error_message
38963  << "The global index for the ("<< rlef <<")-th face element "
38964  << "on\nthe ("<< bound <<")-th boundary was not found "
38965  << "(repeated face element)!!!";
38966  throw OomphLibError(error_message.str(),
38967  OOMPH_CURRENT_FUNCTION,
38968  OOMPH_EXCEPTION_LOCATION);
38969  }
38970 #endif
38971 
38972  // Choose the minimum target area from both elements, one
38973  // at each side of the edge on the boundary
38974  zeta_target_area_values[1] =
38975  std::min(target_area_face_element,
38976  target_area_repeated_face_element);
38977 
38978  // Add the target areas to the sorted set
38979  sorted_target_areas.insert(zeta_target_area_values);
38980 
38981  break;
38982  }
38983 
38984  } // if (!face_element_done[[ele_face_pt])
38985  } // for (iiface<nnon_halo_doubled_face_ele)
38986  }while(face_element_added &&
38987  (nsorted_face_elements < nnon_halo_doubled_face_ele));
38988 
38989  // -------------------------------------------------------------
38990  // At this point we already have a sorted set of nodes and can
38991  // be used to peform the unrefinement and refinement procedures
38992  // -------------------------------------------------------------
38993 
38994  // Get the number of nodes on the list
38995  const unsigned nlocal_nodes = local_vertex_nodes.size();
38996  // Change representation to vector for easy of handling ...
38997  local_tmp_vector_vertex_node.resize(nlocal_nodes);
38998 
38999  // Copy the vertices of the nodes
39000  unsigned counter = 0;
39001  std::set<Vector<double> >::iterator it_vertex;
39002  for (it_vertex = local_vertex_nodes.begin();
39003  it_vertex != local_vertex_nodes.end();
39004  it_vertex++)
39005  {
39006  local_tmp_vector_vertex_node[counter].resize(3);
39007  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
39008  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
39009  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
39010  counter++;
39011  }
39012 
39013  // ... same for the info. related with the target areas (turn
39014  // into vector)
39015  const unsigned ntarget_areas = sorted_target_areas.size();
39016  tmp_sorted_target_areas.resize(ntarget_areas);
39017  counter = 0;
39018  std::set<Vector<double> >::iterator it_area;
39019  for(it_area = sorted_target_areas.begin();
39020  it_area != sorted_target_areas.end();
39021  ++it_area)
39022  {
39023  tmp_sorted_target_areas[counter] = (*it_area)[1];
39024  ++counter;
39025  }
39026 
39027 #ifdef PARANOID
39028  if (nlocal_nodes > 0 && (ntarget_areas != nlocal_nodes - 1) )
39029  {
39030  std::ostringstream error_message;
39031  error_message
39032  << "The boundary (" << bound << ") was split during the "
39033  << "distribution process.\n"
39034  << "The problem comes when associating the target areas with the "
39035  << "elements that gave\nrise to the vertex coordinates.\n"
39036  << "The number of local nodes on the 'sub-polyline' ("
39037  << nlocal_nodes << ") is not according with the number of target\n"
39038  << "areas ("<< ntarget_areas << ") for that number of nodes.\n"
39039  << "The target areas number must be equal to the number of nodes-1\n";
39040  throw OomphLibError(error_message.str(),
39041  OOMPH_CURRENT_FUNCTION,
39042  OOMPH_EXCEPTION_LOCATION);
39043  }
39044 #endif
39045 
39046  // The unrefinement and refinement process needs to be applied
39047  // from the bottom-left node since the internal open curve could
39048  // lie on the shared boundaries
39049  if (local_tmp_vector_vertex_node[nlocal_nodes-1][2] <
39050  local_tmp_vector_vertex_node[0][2])
39051  {
39052  std::reverse(local_tmp_vector_vertex_node.begin(),
39053  local_tmp_vector_vertex_node.end());
39054  std::reverse(tmp_sorted_target_areas.begin(),
39055  tmp_sorted_target_areas.end());
39056  }
39057  else if (local_tmp_vector_vertex_node[nlocal_nodes-1][2] ==
39058  local_tmp_vector_vertex_node[0][2])
39059  {
39060  if (local_tmp_vector_vertex_node[nlocal_nodes-1][1] <
39061  local_tmp_vector_vertex_node[0][1])
39062  {
39063  std::reverse(local_tmp_vector_vertex_node.begin(),
39064  local_tmp_vector_vertex_node.end());
39065  std::reverse(tmp_sorted_target_areas.begin(),
39066  tmp_sorted_target_areas.end());
39067  }
39068  }
39069 
39070  // ------------------------------------------------------------
39071  // Create the vertices along the boundary using the target
39072  // area to define the distance among them
39073  // ------------------------------------------------------------
39074 
39075  // Tolerance below which the middle point can be deleted
39076  // (ratio of deflection to element length)
39077  double unrefinement_tolerance=
39078  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
39079 
39080  // Apply unrefinement
39081  bool unrefinement_applied =
39082  unrefine_boundary_constrained_by_target_area(
39083  bound, chunk, local_tmp_vector_vertex_node,
39084  unrefinement_tolerance, tmp_sorted_target_areas);
39085 
39086  // Tolerance for refinement
39087  double refinement_tolerance=
39088  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
39089 
39090  // Apply refinement
39091  bool refinement_applied =
39092  refine_boundary_constrained_by_target_area(
39093  mesh_geom_obj_pt, local_tmp_vector_vertex_node,
39094  refinement_tolerance, tmp_sorted_target_areas);
39095 
39096  // Clear the local containter to recover the nodes ordered using
39097  // the zeta value
39098  local_vertex_nodes.clear();
39099 
39100  // At the end of each unrefinement/refinement step store the new
39101  // nodes on the set that will give rise to the vertices of the
39102  // new polyline representation
39103  const unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
39104  for (unsigned i = 0; i < nnew_nodes; i++)
39105  {
39106  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
39107  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
39108  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
39109  vertex_nodes.insert(vertex_coord); // Global container
39110  local_vertex_nodes.insert(vertex_coord);
39111  }
39112 
39113  // Update the flag to indicate whether an unrefinement or
39114  // refinement was applied
39115  update_was_performed = (unrefinement_applied || refinement_applied);
39116 
39117 #ifdef OOMPH_HAS_MPI
39118  if (this->is_mesh_distributed())
39119  {
39120  // Add the set of vertices for the boundary, this will help to
39121  // detect if we need to deal with sub_boundaries and
39122  // sub_polylines representations
39123  sub_vertex_nodes.push_back(local_vertex_nodes);
39124  // Increase the counter for sub_boundaries
39125  nsub_boundaries++;
39126 
39127  // Mark if the polyline created by these vertices will be used
39128  // as a shared boundary or as an internal boundary
39129  if (both_root_face_elements_are_nonhalo)
39130  {internal_to_shared_boundary.push_back(false);}
39131  else
39132  {internal_to_shared_boundary.push_back(true);}
39133  }
39134 #endif
39135 
39136  } // while(nsorted_face_elements < nnon_halo_doubled_face_ele)
39137  // This while is in charge of sorting all the face elements to
39138  // create the new representation of the polyline (also deals
39139  // with the sub-boundary cases)
39140 
39141  // Now turn into vector for ease of handling...
39142  const unsigned npoly_vertex = vertex_nodes.size();
39143  tmp_vector_vertex_node.resize(npoly_vertex);
39144  unsigned count = 0;
39145  for (std::set<Vector<double> >::iterator it = vertex_nodes.begin();
39146  it!=vertex_nodes.end(); ++it)
39147  {
39148  tmp_vector_vertex_node[count].resize(3);
39149  tmp_vector_vertex_node[count][0] = (*it)[0];
39150  tmp_vector_vertex_node[count][1] = (*it)[1];
39151  tmp_vector_vertex_node[count][2] = (*it)[2];
39152  ++count;
39153  }
39154 
39155 #ifdef OOMPH_HAS_MPI
39156  // Check that the number of set of vertices marked to be part of a
39157  // shared boundary or of an internal boundaries be the same as the
39158  // total number of sub-boundaries
39159 #ifdef PARANOID
39160  const unsigned nsub_boundaries_set = sub_vertex_nodes.size();
39161  const unsigned ninternal_to_shared_boundaries =
39162  internal_to_shared_boundary.size();
39163  if (nsub_boundaries_set != ninternal_to_shared_boundaries)
39164  {
39165  std::ostringstream error_message;
39166  error_message
39167  << "The number of found sub-boundaries and the number of marked "
39168  << "internal\nboundaries are different\n"
39169  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
39170  << "Number of marked internal boundaries: ("
39171  << ninternal_to_shared_boundaries << ")\n\n";
39172  throw OomphLibError(error_message.str(),
39173  OOMPH_CURRENT_FUNCTION,
39174  OOMPH_EXCEPTION_LOCATION);
39175  }
39176 #endif
39177 
39178  // --------- Stuff for the sub_boundaries ----- Begin section -------
39179 #ifdef PARANOID
39180  if (nsub_boundaries_set != nsub_boundaries)
39181  {
39182  std::ostringstream error_message;
39183  error_message
39184  << "The number of found sub-boundaries and the number of counted\n"
39185  << "sub-boundaries are different:\n"
39186  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
39187  << "Number of counted sub-boundaries: ("<<nsub_boundaries<<")\n\n";
39188  throw OomphLibError(error_message.str(),
39189  OOMPH_CURRENT_FUNCTION,
39190  OOMPH_EXCEPTION_LOCATION);
39191  }
39192 #endif
39193 
39194  // Verify if need to deal with sub_boundaries
39195  if (this->is_mesh_distributed() && nsub_boundaries > 1)
39196  {
39197  // Mark the boundary as been splitted in the partition process
39198  this->Boundary_was_splitted[bound] = true;
39199 
39200  // Resize the vector to store the info. of sub-boundaries
39201  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
39202  // Loop over the sub-boundaries
39203  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39204  {
39205  // Turn info. into vector for ease of handling...
39206  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
39207  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
39208  unsigned subcount = 0;
39209  std::set<Vector<double> >::iterator subit;
39210  for(subit = sub_vertex_nodes[isub].begin();
39211  subit != sub_vertex_nodes[isub].end(); ++subit)
39212  {
39213  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
39214  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
39215  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
39216  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
39217  ++subcount;
39218  }
39219  }
39220  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39221  // --------- Stuff for the sub_boundaries ----- End section ----------
39222 #endif // OOMPH_HAS_MPI
39223 
39224  // For further processing the three-dimensional vector has to be
39225  // reduced to a two-dimensional vector
39226  unsigned n_vertex=tmp_vector_vertex_node.size();
39227 
39228  // Resize the vector for vectices
39229  vector_vertex_node.resize(n_vertex);
39230  for(unsigned i=0;i<n_vertex;i++)
39231  {
39232  vector_vertex_node[i].resize(2);
39233  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
39234  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
39235  }
39236 
39237 #ifdef OOMPH_HAS_MPI
39238  // --------- Stuff for the sub_boundaries ----- Begin section -------
39239  // Verify if need to deal with sub_boundaries
39240  if (this->is_mesh_distributed() && nsub_boundaries > 1)
39241  {
39242  // For further processing the three-dimensional vector has to be
39243  // reduced to a two-dimensional vector
39244  // Resize the vector to store the info. of sub-boundaries
39245  sub_vector_vertex_node.resize(nsub_boundaries);
39246  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39247  {
39248  const unsigned subn_vertex =
39249  sub_tmp_vector_vertex_node[isub].size();
39250  // Resize the vector for vectices
39251  sub_vector_vertex_node[isub].resize(subn_vertex);
39252  for(unsigned i=0;i<subn_vertex;i++)
39253  {
39254  sub_vector_vertex_node[isub][i].resize(2);
39255  sub_vector_vertex_node[isub][i][0]=
39256  sub_tmp_vector_vertex_node[isub][i][1];
39257  sub_vector_vertex_node[isub][i][1]=
39258  sub_tmp_vector_vertex_node[isub][i][2];
39259  }
39260  }
39261  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39262 
39263  // We already have the info. for the sub-boundaries (if necessary)
39264  // and then we can create the sub-boundaries representations to
39265  // ease the generation of the mesh by Triangle
39266 
39267  // --------- Stuff for the sub_boundaries ----- End section ---------
39268 #endif // OOMPH_HAS_MPI
39269 
39270  // ------------------------------------------------------------------
39271  // Check for contiguousness
39272  // ------------------------------------------------------------------
39273 #ifdef OOMPH_HAS_MPI
39274  // Only perform this checking if the mesh is not distributed When
39275  // the mesh is distributed the polylines continuity is addressed by
39276  // the sort_polylines_helper() method
39277  if (!this->is_mesh_distributed())
39278 #endif
39279  {
39280  if ( cs > 0 )
39281  {
39282  //Final end point of previous line
39283  Vector<double> final_vertex_of_previous_segment;
39284  unsigned n_prev_vertex =
39285  open_curve_pt->curve_section_pt(cs-1)->nvertex();
39286  final_vertex_of_previous_segment =
39287  open_curve_pt->polyline_pt(cs-1)->
39288  vertex_coordinate(n_prev_vertex-1);
39289 
39290  unsigned prev_seg_boundary_id =
39291  open_curve_pt->curve_section_pt(cs-1)->boundary_id();
39292 
39293  //Find the error between the final vertex of the previous
39294  //line and the first vertex of the current line
39295  double error = 0.0;
39296  for(unsigned i=0;i<2;i++)
39297  {
39298  const double dist =
39299  final_vertex_of_previous_segment[i] -
39300  (*vector_vertex_node.begin())[i];
39301  error += dist*dist;
39302  }
39303  error = sqrt(error);
39304 
39305  //If the error is bigger than the tolerance then
39306  //we probably need to reverse, but better check
39308  {
39309  //Find the error between the final vertex of the previous
39310  //line and the last vertex of the current line
39311  double rev_error = 0.0;
39312  for(unsigned i=0;i<2;i++)
39313  {
39314  const double dist =
39315  final_vertex_of_previous_segment[i] -
39316  (*--vector_vertex_node.end())[i];
39317  rev_error += dist*dist;
39318  }
39319  rev_error = sqrt(rev_error);
39320 
39321  if(rev_error >
39323  {
39324  // It could be possible that the first segment be reversed and we
39325  // did not notice it because this check does not apply for the
39326  // first segment. We can verify if the first segment is reversed
39327  // by using the vertex number 1
39328  if (cs == 1)
39329  {
39330  //Initial end point of previous line
39331  Vector<double> initial_vertex_of_previous_segment;
39332 
39333  initial_vertex_of_previous_segment =
39334  open_curve_pt->polyline_pt(cs-1)->vertex_coordinate(0);
39335 
39336  unsigned prev_seg_boundary_id =
39337  open_curve_pt->curve_section_pt(cs-1)->boundary_id();
39338 
39339  //Find the error between the initial vertex of the previous
39340  //line and the first vertex of the current line
39341  double error = 0.0;
39342  for(unsigned i=0;i<2;i++)
39343  {
39344  const double dist =
39345  initial_vertex_of_previous_segment[i] -
39346  (*vector_vertex_node.begin())[i];
39347  error += dist*dist;
39348  }
39349  error = sqrt(error); // Reversed only the previous one
39350 
39351  //If the error is bigger than the tolerance then
39352  //we probably need to reverse, but better check
39354  {
39355  //Find the error between the final vertex of the previous
39356  //line and the last vertex of the current line
39357  double rev_error = 0.0;
39358  for(unsigned i=0;i<2;i++)
39359  {
39360  const double dist =
39361  initial_vertex_of_previous_segment[i] -
39362  (*--vector_vertex_node.end())[i];
39363  rev_error += dist*dist;
39364  }
39365  rev_error = sqrt(rev_error); // Reversed both the current
39366  // one and the previous one
39367 
39368  if (rev_error >
39370  {
39371  std::ostringstream error_stream;
39372  error_stream
39373  <<"The distance between the first node of the current\n"
39374  <<"line segment (boundary "<<bound<<") and either end of "
39375  <<"the previous line segment\n"
39376  <<"(boundary "<<prev_seg_boundary_id<<") is bigger than"
39377  << " the desired tolerance " <<
39379  <<"This suggests that the polylines defining the polygonal\n"
39380  <<"representation are not properly ordered.\n"
39381  <<"Fail on last vertex of polyline: ("
39382  <<prev_seg_boundary_id<<") and\nfirst vertex of polyline ("
39383  <<bound<< ").\nThis should have failed when first trying to "
39384  <<"construct the\npolygon.\n";
39385  throw OomphLibError(error_stream.str(),
39386  OOMPH_CURRENT_FUNCTION,
39387  OOMPH_EXCEPTION_LOCATION);
39388  }
39389  else
39390  {
39391  // Reverse both
39392  // Reverse the current vector to line up with the previous one
39393  std::reverse(vector_vertex_node.begin(),
39394  vector_vertex_node.end());
39395  open_curve_pt->polyline_pt(cs-1)->reverse();
39396  }
39397  }
39398  else
39399  {
39400  // Reverse the previous one
39401  open_curve_pt->polyline_pt(cs-1)->reverse();
39402  }
39403 
39404  } // if (cs == 1)
39405  else
39406  {
39407  std::ostringstream error_stream;
39408  error_stream
39409  <<"The distance between the first node of the current\n"
39410  <<"line segment (boundary " << bound << ") and either end of "
39411  <<"the previous line segment\n"
39412  <<"(boundary "<<prev_seg_boundary_id<<") is bigger than the "
39413  <<"desired tolerance " <<
39415  <<"This suggests that the polylines defining the polygonal\n"
39416  <<"representation are not properly ordered.\n"
39417  <<"Fail on last vertex of polyline: ("<<prev_seg_boundary_id
39418  <<") and\nfirst vertex of polyline (" <<bound << ").\n"
39419  <<"This should have failed when first trying to construct\n"
39420  << "the polygon.\n";
39421  throw OomphLibError(error_stream.str(),
39422  OOMPH_CURRENT_FUNCTION,
39423  OOMPH_EXCEPTION_LOCATION);
39424  }
39425  }
39426  else
39427  {
39428  //Reverse the current vector to line up with the previous one
39429  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
39430  }
39431 
39432  }
39433 
39434  } // if (cs > 0)
39435 
39436  } // if (!this->is_mesh_distributed())
39437 
39438  // ---------------------------------------------------------------
39439  // Update the polylines representation
39440  // ---------------------------------------------------------------
39441  // Always update the polylines representation, in a distributed
39442  // mesh it is necessary to update the polyline representation since
39443  // it may no longer have vertices (the boundary may not be part of
39444  // the domain in the current processor)
39445 
39446  // The new number of vertices
39447  n_vertex = vector_vertex_node.size();
39448 
39449  // Update the polyline according to the new vertices
39450  TriangleMeshPolyLine *tmp_polyline_pt =
39451  new TriangleMeshPolyLine(vector_vertex_node,bound);
39452 
39453  // Create a temporal "curve section" version of the recently
39454  // created polyline
39455  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
39456 
39457  // Tolerance below which the middle point can be deleted (ratio of
39458  // deflection to element length)
39459  double unrefinement_tolerance=
39460  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
39461 
39462  // Tolerance to add points
39463  double refinement_tolerance=
39464  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
39465 
39466  // Establish refinement and unrefinement tolerance
39467  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
39468  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
39469 
39470  // Establish the maximum length constraint
39471  double maximum_length = open_curve_pt->polyline_pt(cs)->maximum_length();
39472  tmp_polyline_pt->set_maximum_length(maximum_length);
39473 
39474 #ifdef OOMPH_HAS_MPI
39475  // If the mesh is distributed check that the polyline still has
39476  // vertices
39477  if (this->is_mesh_distributed())
39478  {
39479  if (n_vertex >= 2)
39480  {
39481  // Pass the connection information from the old polyline to
39482  // the new one
39483  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
39484  tmp_curve_section_pt);
39485  } // if (n_vertex >= 2)
39486  } // if (this->is_mesh_distributed())
39487  else
39488 #endif
39489  {
39490  // Pass the connection information from the old polyline to the
39491  // new one
39492  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
39493  tmp_curve_section_pt);
39494  }
39495 
39496  // Now update the polyline according to the new vertices but first
39497  // check if the object is allowed to delete the representation or
39498  // if it should be done by other object
39499  bool delete_it_on_destructor = false;
39500 
39501  std::set<TriangleMeshCurveSection*>::iterator it =
39502  this->Free_curve_section_pt.find(open_curve_pt->curve_section_pt(cs));
39503 
39504  if (it!=this->Free_curve_section_pt.end())
39505  {
39506  this->Free_curve_section_pt.erase(it);
39507  delete open_curve_pt->curve_section_pt(cs);
39508  delete_it_on_destructor = true;
39509  }
39510 
39511  // -------------------------------------------------------------
39512  // Copying the new representation
39513  open_curve_pt->curve_section_pt(cs) = tmp_polyline_pt;
39514 
39515  // Update the Boundary - Polyline map
39516  this->Boundary_curve_section_pt[bound] =
39517  open_curve_pt->curve_section_pt(cs);
39518 
39519  if (delete_it_on_destructor)
39520  {
39521  this->Free_curve_section_pt.insert(open_curve_pt->curve_section_pt(cs));
39522  }
39523 
39524 #ifdef OOMPH_HAS_MPI
39525  // If there are not sub-boundaries mark the boundary if need to be
39526  // trated as shared or as internal boundary
39527  if (this->is_mesh_distributed() && nsub_boundaries == 1)
39528  {
39529  // Clear all previous stored data
39530  this->Boundary_marked_as_shared_boundary[bound].clear();
39531 
39532  // .. and store the flag for the boundary
39533  this->Boundary_marked_as_shared_boundary[bound].push_back(
39534  internal_to_shared_boundary[0]);
39535  }
39536  // --------- Stuff for the sub_boundaries ----- Begin section --------
39537  // Verify if need to deal with sub_boundaries
39538  else if (this->is_mesh_distributed() && nsub_boundaries > 1)
39539  {
39540  // Create temporary representations for the boundaries, only to
39541  // create the mesh when calling Triangle
39542 
39543  // Clear all previous stored data
39544  this->Boundary_subpolylines[bound].clear();
39545  // Now create storage for the sub-boundaries
39546  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
39547 
39548  // Clear all previous stored data
39549  this->Boundary_marked_as_shared_boundary[bound].clear();
39550  // Create storage to mark the internal boundaries as shared
39551  // boundaries
39552  this->Boundary_marked_as_shared_boundary[bound].resize(nsub_boundaries);
39553  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39554  {
39555  // Now update the polyline according to the sub set of
39556  // vertices, set the chunk number of the polyline
39557  TriangleMeshPolyLine *sub_tmp_polyline_pt =
39558  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
39559 
39560  // Add the sub-polyline to the container to represent the
39561  // boundary in parts
39562  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
39563 
39564  // Copy the flag that mark the boundary as internal or as
39565  // shared bound
39566  this->Boundary_marked_as_shared_boundary[bound][isub] =
39567  internal_to_shared_boundary[isub];
39568 
39569  // No need to send the unrefinement/refinement and maximum
39570  // length constraints since these are only temporary
39571  // representations
39572 
39573  // But we certanly we need to pass the connection information
39574  // to the sub-polylines
39575  // Get a curve section representation of the sub-polyline
39576  TriangleMeshCurveSection *tmp_sub_curve_section_pt =
39577  sub_tmp_polyline_pt;
39578  this->copy_connection_information_to_sub_polylines(
39579  tmp_curve_section_pt, tmp_sub_curve_section_pt);
39580 
39581  } // for (isub < nsub_boundaries)
39582 
39583  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39584  // --------- Stuff for the sub_boundaries ----- End section ---------
39585 #endif // OOMPH_HAS_MPI
39586 
39587  // Delete the allocated memory for the geometric object
39588  // that represents the curvilinear boundary
39589  delete mesh_geom_obj_pt;
39590 
39591  } // for (cs < ncurve_section)
39592 
39593  // Cleanup the face mesh
39594  for(unsigned p = 0; p < ncurve_section; p++)
39595  {
39596  face_mesh_pt[p]->flush_node_storage();
39597  delete face_mesh_pt[p];
39598  }
39599 
39600  return update_was_performed;
39601 
39602 }
39603 
39604 #ifdef OOMPH_HAS_MPI
39605 //======================================================================
39606 /// \short Updates the polylines using the elements area as
39607 /// constraint for the number of points along the boundaries
39608 //======================================================================
39609 template <class ELEMENT>
39612  &vector_polyline_pt,
39613  const Vector<double> &target_areas)
39614 {
39615  // Flag to check if there were a change on the shared boundary
39616  // representation
39617  unsigned update_was_performed = false;
39618 
39619  // Go through all the shared boundaries/polylines
39620  const unsigned n_polylines = vector_polyline_pt.size();
39621  for (unsigned pp = 0; pp < n_polylines; pp++)
39622  {
39623  // Get the boundary id of the current polyline
39624  const unsigned shd_bnd_id = vector_polyline_pt[pp]->boundary_id();
39625 
39626  // Get the chunk number
39627  const unsigned chunk = vector_polyline_pt[pp]->boundary_chunk();
39628 
39629  // Get the face elements that created the shared boundary from the
39630  // bulk shared boundary elements
39631 
39632  // Compute the face elements from the shared boundary elements,
39633  // create an association from the face element with the "bulk"
39634  // elements
39635  std::map<FiniteElement*, FiniteElement*> face_ele_pt_to_bulk_element_pt;
39636 
39637  // The temporary storage for the halo face elements
39638  Vector<FiniteElement*> halo_shared_face_ele_pt;
39639  // The temporary storage for the nonhalo face elements
39640  Vector<FiniteElement*> nonhalo_shared_face_ele_pt;
39641 
39642  // Get the number of shared boundary elements associated with the
39643  // current shared boundary
39644  const unsigned nshared_bound_ele =
39645  this->nshared_boundary_element(shd_bnd_id);
39646 
39647  // Loop over the elements in the shared boundary to create the face
39648  // elements
39649  for (unsigned e = 0; e < nshared_bound_ele; e++)
39650  {
39651  // Get the shared boundary element
39652  FiniteElement* bulk_ele_pt =
39653  this->shared_boundary_element_pt(shd_bnd_id, e);
39654 
39655  // Get the face index
39656  int face_index = this->face_index_at_shared_boundary(shd_bnd_id, e);
39657 
39658  // Before adding the new element we need to ensure that the edge
39659  // that this element represents has not been already added
39660  FiniteElement* face_ele_pt =
39661  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
39662 
39663  // Establish the association between the bulk element and the
39664  // face element
39665  face_ele_pt_to_bulk_element_pt[face_ele_pt] = bulk_ele_pt;
39666 
39667  // Nonhalo element
39668  if (!bulk_ele_pt->is_halo())
39669  {
39670  // Add nonhalo shared face element to the container
39671  nonhalo_shared_face_ele_pt.push_back(face_ele_pt);
39672  }
39673  else // halo element
39674  {
39675  // Add halo shared face element to the container
39676  halo_shared_face_ele_pt.push_back(face_ele_pt);
39677  }
39678 
39679  } // for (e < nshared_bound_ele)
39680 
39681  // Now we have the face elements, we need to ensure that the halo
39682  // and nonhalo bulk element are sorted one after the other
39683  Vector<Vector<FiniteElement*> > unsorted_shared_bulk_ele_pt;
39684 
39685  // Mark the face elements already used
39686  std::map<FiniteElement*, bool> shared_face_done;
39687 
39688  // Get the number of nonhalo face elements
39689  const unsigned nnonhalo_face_shared_ele =
39690  nonhalo_shared_face_ele_pt.size();
39691 
39692  // Get the number of halo face elements
39693  const unsigned nhalo_face_shared_ele =
39694  halo_shared_face_ele_pt.size();
39695 
39696 #ifdef PARANOID
39697  // The number of nonhalo shared face boundary elements must be the
39698  // half of the total number of shared boundary elements
39699  if (nshared_bound_ele / 2 != nnonhalo_face_shared_ele)
39700  {
39701  std::ostringstream error_message;
39702  error_message
39703  << "The number of shared boundary elements (" << nshared_bound_ele
39704  << ") is not the double\nof the number of unsorted NONHALO shared "
39705  << "face boundary elements (" << nnonhalo_face_shared_ele << ")\n"
39706  << "for the current boundary ("<< shd_bnd_id << ")\n\n";
39707  throw OomphLibError(error_message.str(),
39708  OOMPH_CURRENT_FUNCTION,
39709  OOMPH_EXCEPTION_LOCATION);
39710  }
39711 
39712  // The number of halo shared face boundary elements must be the
39713  // half of the total number of shared boundary elements
39714  if (nshared_bound_ele / 2 != nhalo_face_shared_ele)
39715  {
39716  std::ostringstream error_message;
39717  error_message
39718  << "The number of shared boundary elements (" << nshared_bound_ele
39719  << ") is not the double\nof the number of unsorted HALO shared "
39720  << "face boundary elements (" << nhalo_face_shared_ele << ")\n"
39721  << "for the current boundary ("<< shd_bnd_id << ")\n\n";
39722  throw OomphLibError(error_message.str(),
39723  OOMPH_CURRENT_FUNCTION,
39724  OOMPH_EXCEPTION_LOCATION);
39725  }
39726 #endif
39727 
39728  // ------------------------------------------------------------------
39729  // Loop over the nonhalo face elements and look for the halo face
39730  // element at the other side of the shared boundary
39731  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
39732  {
39733  // Get the inh-th face element
39734  FiniteElement* nonhalo_face_ele_pt = nonhalo_shared_face_ele_pt[inh];
39735 
39736  // Get the number of nodes on the face element
39737  const unsigned nnodes_nh = nonhalo_face_ele_pt->nnode();
39738  // Get the first and last node on the element
39739  Node* nh_first_node_pt = nonhalo_face_ele_pt->node_pt(0);
39740  Node* nh_last_node_pt = nonhalo_face_ele_pt->node_pt(nnodes_nh-1);
39741 
39742  // Now find the (halo) face element at the other side of the
39743  // shared boundary
39744  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
39745  {
39746  // Get the ih-th face element
39747  FiniteElement* halo_face_ele_pt = halo_shared_face_ele_pt[ih];
39748 
39749  // Check that the face element has not been done
39750  if (!shared_face_done[halo_face_ele_pt])
39751  {
39752  // Get the number of nodes on the face element
39753  const unsigned nnodes_h = halo_face_ele_pt->nnode();
39754  // Get the first and last node on the element
39755  Node* h_first_node_pt = halo_face_ele_pt->node_pt(0);
39756  Node* h_last_node_pt = halo_face_ele_pt->node_pt(nnodes_h-1);
39757 
39758  // If the nodes are the same then we have found the (halo)
39759  // face element at the other side of the shared boundary
39760  if (nh_first_node_pt == h_first_node_pt &&
39761  nh_last_node_pt == h_last_node_pt)
39762  {
39763  // Get the BULK elements associated with the face elements
39764  Vector<FiniteElement*> tmp_bulk_element_pt;
39765  // Get the BULK elements associated to the face elements
39766  // (the nonhalo and the halo)
39767  FiniteElement* nonhalo_bulk_ele_pt =
39768  face_ele_pt_to_bulk_element_pt[nonhalo_face_ele_pt];
39769  FiniteElement* halo_bulk_ele_pt =
39770  face_ele_pt_to_bulk_element_pt[halo_face_ele_pt];
39771 
39772  // Add the BULK elements to the temporal storage
39773  tmp_bulk_element_pt.push_back(nonhalo_bulk_ele_pt);
39774  tmp_bulk_element_pt.push_back(halo_bulk_ele_pt);
39775 
39776  // Store the pair of elements associated to the "edge"
39777  unsorted_shared_bulk_ele_pt.push_back(tmp_bulk_element_pt);
39778 
39779  // Mark the face elements as done
39780  shared_face_done[nonhalo_face_ele_pt] = true;
39781  shared_face_done[halo_face_ele_pt] = true;
39782 
39783  // Break the loop for (ih < nhalo_face_shared_ele)
39784  break;
39785  } // if (nh_first_node_pt == h_first_node_pt &&
39786  // nh_last_node_pt == h_last_node_pt)
39787  else if (nh_first_node_pt == h_last_node_pt &&
39788  nh_last_node_pt == h_first_node_pt)
39789  {
39790  // Get the BULK elements associated with the face elements
39791  Vector<FiniteElement*> tmp_bulk_element_pt;
39792  // Get the BULK elements associated to the face elements
39793  // (the nonhalo and the halo)
39794  FiniteElement* nonhalo_bulk_ele_pt =
39795  face_ele_pt_to_bulk_element_pt[nonhalo_face_ele_pt];
39796  FiniteElement* halo_bulk_ele_pt =
39797  face_ele_pt_to_bulk_element_pt[halo_face_ele_pt];
39798 
39799  // Add the BULK elements to the temporal storage
39800  tmp_bulk_element_pt.push_back(nonhalo_bulk_ele_pt);
39801  tmp_bulk_element_pt.push_back(halo_bulk_ele_pt);
39802 
39803  // Store the pair of elements associated to the "edge"
39804  unsorted_shared_bulk_ele_pt.push_back(tmp_bulk_element_pt);
39805 
39806  // Mark the face elements as done
39807  shared_face_done[nonhalo_face_ele_pt] = true;
39808  shared_face_done[halo_face_ele_pt] = true;
39809 
39810  // Break the loop for (ih < nhalo_face_shared_ele)
39811  break;
39812  } // else if (nh_first_node_pt == h_last_node_pt &&
39813  // nh_last_node_pt == h_first_node_pt)
39814 
39815  } // if (face_done[halo_face_ele_pt])
39816 
39817  } // for (ih < nhalo_face_shared_ele)
39818 
39819  } // for (inh < nnonhalo_face_shared_ele)
39820 
39821  // -------------------------------------------------------------
39822  // Now sort the face elements
39823  // -------------------------------------------------------------
39824 
39825  // We already have the shared face elements that make the shared
39826  // boundary (and the bulk elements), now sort them to create a
39827  // contiguous boundary
39828 
39829 #ifdef PARANOID
39830  const unsigned nunsorted_shared_bulk_ele =
39831  unsorted_shared_bulk_ele_pt.size();
39832 
39833  // The number of unsorted shared BULK elements MUST be the same
39834  // as the number of shared_boundary elements divided by two
39835  if (nshared_bound_ele / 2 != nunsorted_shared_bulk_ele)
39836  {
39837  std::ostringstream error_message;
39838  error_message
39839  << "The number of shared boundary elements (" << nshared_bound_ele
39840  << ") is not the double\nof the number of unsorted shared bulk "
39841  << "boundary elements (" << nunsorted_shared_bulk_ele << ")\n"
39842  << "for the current boundary ("<< shd_bnd_id << ")\n\n";
39843  throw OomphLibError(error_message.str(),
39844  OOMPH_CURRENT_FUNCTION,
39845  OOMPH_EXCEPTION_LOCATION);
39846  }
39847 
39848  // The number of done shared face elements MUST be the same as the
39849  // sum of the nonhalo and halo shared boundary face elements
39850  if ((nnonhalo_face_shared_ele + nhalo_face_shared_ele) !=
39851  shared_face_done.size())
39852  {
39853  std::ostringstream error_message;
39854  error_message
39855  << "The number of DONE shared boundary face elements ("
39856  << shared_face_done.size() << ") is not the same\n as the sum of"
39857  << "the nonhalo face shared boundary elements ("
39858  << nnonhalo_face_shared_ele << ")\nand the halo face shared "
39859  << "boundary elements ("<< nhalo_face_shared_ele << ") for the\n/"
39860  << "current boundary (" << shd_bnd_id << ")\n\n";
39861  throw OomphLibError(error_message.str(),
39862  OOMPH_CURRENT_FUNCTION,
39863  OOMPH_EXCEPTION_LOCATION);
39864  }
39865 #endif
39866 
39867  // Clear the already done face elements
39868  shared_face_done.clear();
39869 
39870  // The number of sorted face elements
39871  unsigned nsorted_face_ele = 0;
39872 
39873  // Storing for the sorting nodes extracted from the face
39874  // elements. This are also used to update the polyline
39875  std::list<Node*> sorted_nodes;
39876 
39877  // Storing for the sorted shared face elements
39878  std::list<FiniteElement*> sorted_shared_bound_elements_pt;
39879 
39880  // Get the root face element
39881  FiniteElement* root_face_ele_pt = nonhalo_shared_face_ele_pt[0];
39882  nsorted_face_ele++;
39883 
39884  // Mark face as done
39885  shared_face_done[root_face_ele_pt] = true;
39886 
39887  // The initial and final node on the list
39888  const unsigned nnodes_root = root_face_ele_pt->nnode();
39889  Node *first_node_pt = root_face_ele_pt->node_pt(0);
39890  Node *last_node_pt = root_face_ele_pt->node_pt(nnodes_root-1);
39891 
39892  // Push back on the list the new nodes
39893  sorted_nodes.push_back(first_node_pt);
39894  sorted_nodes.push_back(last_node_pt);
39895 
39896  // Store the bulk elements of the current face
39897  sorted_shared_bound_elements_pt.push_back(
39898  unsorted_shared_bulk_ele_pt[0][0]);
39899  sorted_shared_bound_elements_pt.push_back(
39900  unsorted_shared_bulk_ele_pt[0][1]);
39901 
39902  // Sort the face elements
39903  while (nsorted_face_ele < nnonhalo_face_shared_ele)
39904  {
39905  // Flag to indicate when a node was added
39906  bool node_added = false;
39907 
39908  // Start from the next edge since we have already added the
39909  // previous one as the initial face element
39910  for (unsigned iface = 1; iface < nnonhalo_face_shared_ele; iface++)
39911  {
39912  FiniteElement* tmp_shared_face_ele_pt =
39913  nonhalo_shared_face_ele_pt[iface];
39914 
39915  // If face has not been sorted
39916  if (!shared_face_done[tmp_shared_face_ele_pt])
39917  {
39918  // Get the number of nodes for the current face element
39919  const unsigned tmp_nnodes = tmp_shared_face_ele_pt->nnode();
39920 
39921  // Get each individual node
39922  Node* left_node_pt = tmp_shared_face_ele_pt->node_pt(0);
39923  Node* right_node_pt = tmp_shared_face_ele_pt->node_pt(tmp_nnodes-1);
39924 
39925  if (left_node_pt == first_node_pt)
39926  {
39927  // Push front the new node
39928  sorted_nodes.push_front(right_node_pt);
39929  first_node_pt = right_node_pt;
39930  node_added = true;
39931 
39932  // Store the elements of the current face element
39933  sorted_shared_bound_elements_pt.push_front(
39934  unsorted_shared_bulk_ele_pt[iface][1]);
39935  sorted_shared_bound_elements_pt.push_front(
39936  unsorted_shared_bulk_ele_pt[iface][0]);
39937  }
39938  else if (left_node_pt == last_node_pt)
39939  {
39940  // Push back the new node
39941  sorted_nodes.push_back(right_node_pt);
39942  last_node_pt = right_node_pt;
39943  node_added = true;
39944 
39945  // Store the elements of the current face element
39946  sorted_shared_bound_elements_pt.push_back(
39947  unsorted_shared_bulk_ele_pt[iface][0]);
39948  sorted_shared_bound_elements_pt.push_back(
39949  unsorted_shared_bulk_ele_pt[iface][1]);
39950  }
39951  else if (right_node_pt == first_node_pt)
39952  {
39953  // Push front the new node
39954  sorted_nodes.push_front(left_node_pt);
39955  first_node_pt = left_node_pt;
39956  node_added = true;
39957 
39958  // Store the elements of the current face element
39959  sorted_shared_bound_elements_pt.push_front(
39960  unsorted_shared_bulk_ele_pt[iface][1]);
39961  sorted_shared_bound_elements_pt.push_front(
39962  unsorted_shared_bulk_ele_pt[iface][0]);
39963  }
39964  else if (right_node_pt == last_node_pt)
39965  {
39966  // Push back the new node
39967  sorted_nodes.push_back(left_node_pt);
39968  last_node_pt = left_node_pt;
39969  node_added = true;
39970 
39971  // Store the elements of the current face element
39972  sorted_shared_bound_elements_pt.push_back(
39973  unsorted_shared_bulk_ele_pt[iface][0]);
39974  sorted_shared_bound_elements_pt.push_back(
39975  unsorted_shared_bulk_ele_pt[iface][1]);
39976  }
39977 
39978  if (node_added)
39979  {
39980  // Mark as done if one of its nodes has been added to the
39981  // list
39982  shared_face_done[tmp_shared_face_ele_pt] = true;
39983  nsorted_face_ele++;
39984 
39985  // Break the for
39986  break;
39987  }
39988 
39989  } // if (!shared_face_done[tmp_shared_face_ele_pt])
39990 
39991  } // for (iface < nnonhalo_face_shared_ele)
39992 
39993  } // while (nsorted_face_ele < nnonhalo_face_shared_ele))
39994 
39995  // ----------------------------------------------------------------
39996  // Here we can safely delete the face elements, they are no longer
39997  // required
39998 
39999  // First the nonhalo face elements
40000  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
40001  {
40002  delete nonhalo_shared_face_ele_pt[inh];
40003  nonhalo_shared_face_ele_pt[inh] = 0;
40004  } // for (inh < nnonhalo_face_shared_ele)
40005 
40006  // ... then the halo face elements
40007  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
40008  {
40009  delete halo_shared_face_ele_pt[ih];
40010  halo_shared_face_ele_pt[ih] = 0;
40011  } // for (inh < nhalo_face_shared_ele)
40012 
40013  // ------------------------------------------------------------------
40014  // At this point we already have a sorted list of nodes, get the
40015  // vertices from them and store them in a vector container
40016 
40017  // Get the number of nodes on the list
40018  const unsigned n_nodes = sorted_nodes.size();
40019 
40020  // The vector to store the vertices
40021  Vector<Vector<double> > polyline_vertices(n_nodes);
40022 
40023  // Copy the vertices from the nodes
40024  unsigned counter = 0;
40025  for (std::list<Node*>::iterator it_nodes = sorted_nodes.begin();
40026  it_nodes != sorted_nodes.end();
40027  it_nodes++)
40028  {
40029  polyline_vertices[counter].resize(2);
40030  polyline_vertices[counter][0] = (*it_nodes)->x(0);
40031  polyline_vertices[counter][1] = (*it_nodes)->x(1);
40032  counter++;
40033  }
40034 
40035  // ------------------------------------------------------------------
40036  // Now get the target areas associated to the shared boundary
40037  // elements
40038 
40039  // Copy the sorted elements in a vector
40040  Vector<FiniteElement*> sorted_shared_ele_pt;
40041  for (std::list<FiniteElement*>::iterator it_ele =
40042  sorted_shared_bound_elements_pt.begin();
40043  it_ele != sorted_shared_bound_elements_pt.end();
40044  it_ele++)
40045  {sorted_shared_ele_pt.push_back((*it_ele));}
40046 
40047  // Get the number of target areas
40048  const unsigned n_shared_target_areas = sorted_shared_ele_pt.size();
40049  Vector<double> sorted_shared_target_areas(n_shared_target_areas);
40050 
40051  // Mark those shared elements already found
40052  std::map<std::pair<GeneralisedElement*, unsigned>, bool> shared_ele_done;
40053 
40054  // Counter for the number of already done shared elements
40055  unsigned count_found_shared_element = 0;
40056 
40057  // Get the target area associated to the shared boundary elements
40058  const unsigned nele = this->nelement();
40059 
40060  // Loop over the elements to find the target areas associated to
40061  // the shared boundary elements
40062  for (unsigned e = 0; e < nele; e++)
40063  {
40064  GeneralisedElement* current_ele_pt = this->element_pt(e);
40065  // Now compare the current element with those in the sorted
40066  // shared element array
40067  for (unsigned s = 0; s < n_shared_target_areas; s++)
40068  {
40069  // Get the element
40070  GeneralisedElement* current_shared_ele_pt = sorted_shared_ele_pt[s];
40071  // Create the pair element-index to check if done
40072  std::pair<GeneralisedElement*, unsigned> pair_gen_ele_idx =
40073  std::make_pair(current_shared_ele_pt, s);
40074  if (!shared_ele_done[pair_gen_ele_idx])
40075  {
40076  // Compare with the global element
40077  if (current_ele_pt == current_shared_ele_pt)
40078  {
40079  // Store the target area of the current shared element
40080  sorted_shared_target_areas[s] = target_areas[e];
40081  // Mark the shared element as done
40082  shared_ele_done[pair_gen_ele_idx] = true;
40083  // Increase the number of found elements
40084  count_found_shared_element++;
40085  } // if (current_ele_pt == current_shared_ele_pt)
40086  } // if (!shared_ele_done[current_shared_ele_pt])
40087  } // for (s < nshared_taget_areas)
40088 
40089  // Check if all shared elements have been found
40090  if (count_found_shared_element == n_shared_target_areas)
40091  {break;}
40092 
40093  } // for (e < nele)
40094 
40095 #ifdef PARANOID
40096  // Check if the number of found target areas is the same as the
40097  // number of shared target areas
40098  if (count_found_shared_element != n_shared_target_areas)
40099  {
40100  std::ostringstream error_message;
40101  error_message
40102  << "The number of found target areas ("
40103  << count_found_shared_element << ") is different from the "
40104  << "total number\nof target areas ("
40105  << n_shared_target_areas << ") in shared boundary ("
40106  << shd_bnd_id <<")\n\n";
40107  throw OomphLibError(error_message.str(),
40108  OOMPH_CURRENT_FUNCTION,
40109  OOMPH_EXCEPTION_LOCATION);
40110  }
40111 #endif
40112 
40113  // The number of vertices
40114  const unsigned n_vertices = n_nodes;
40115 
40116  // Get the number of segments from the input vector_polyline_pt
40117  const unsigned n_segments = vector_polyline_pt[pp]->nsegment();
40118  // Get the number of segments from the input vector_polyline_pt to
40119  // ensure that the shared boundary corresponds to the one
40120  // represented by the shared face elements (this has sence when the
40121  // mesh was re-created from re-starting)
40122 
40123  // Check that the number of vertices correspond with the number of
40124  // segments
40125 #ifdef PARANOID
40126  if (n_segments != n_vertices-1)
40127  {
40128  std::ostringstream error_message;
40129  error_message
40130  << "The number of segments from the current shared polyline "
40131  << "(" << n_segments << ") does not\ncorrespond with the number of "
40132  << "sorted vertices (" << n_vertices-1 << ") of the current shared\n"
40133  << "boundary\n\n";
40134  throw OomphLibError(error_message.str(),
40135  OOMPH_CURRENT_FUNCTION,
40136  OOMPH_EXCEPTION_LOCATION);
40137  }
40138 
40139  // Check that the number of target areas correspond with the number
40140  // of vertices
40141  if (n_segments != n_shared_target_areas/2)
40142  {
40143  std::ostringstream error_message;
40144  error_message
40145  << "The number of segments for the current sorting of edges "
40146  << "(" << n_segments << ") is different\nfrom the number of "
40147  << "target areas (" << n_shared_target_areas/2 << ")\n\n";
40148  throw OomphLibError(error_message.str(),
40149  OOMPH_CURRENT_FUNCTION,
40150  OOMPH_EXCEPTION_LOCATION);
40151  }
40152 #endif
40153 
40154  // ------------------------------------------------------------------
40155  // Get the target areas that are used to perform the unrefinement
40156  // and refinement operation. For each face element on a shared
40157  // polyline there are two bulk elements, a halo and a haloed
40158  // element, each with an associated target area. Review the
40159  // function
40160  // TriangleMesh::create_polylines_from_halo_elements_helper() to
40161  // check how the shared boundaries were created
40162  Vector<double> polyline_target_area(n_segments);
40163  // Loop over the segments in the shared polyline
40164  for (unsigned s = 0; s < n_segments; s++)
40165  {
40166  // Get the minimum of the associated target areas
40167  polyline_target_area[s] = std::min(sorted_shared_target_areas[s*2],
40168  sorted_shared_target_areas[(s*2)+1]);
40169  }
40170 
40171  // Before going to the unrefinement or refinement process check
40172  // that in all processors where the shared boundary lives start
40173  // from the same vertex.
40174  // Start from the bottom left vertex
40175  if (polyline_vertices[n_vertices-1][1] < polyline_vertices[0][1])
40176  {
40177  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
40178  std::reverse(polyline_target_area.begin(), polyline_target_area.end());
40179  }
40180  else if (polyline_vertices[n_vertices-1][1] == polyline_vertices[0][1])
40181  {
40182  if (polyline_vertices[n_vertices-1][0] < polyline_vertices[0][0])
40183  {
40184  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
40185  std::reverse(polyline_target_area.begin(), polyline_target_area.end());
40186  }
40187  }
40188 
40189  // ------------------------------------------------------------------
40190  // Apply unrefinement
40191  bool unrefinement_applied = false;
40192  // Apply unefinement if there are more than three nodes at the
40193  // shared boundary
40194  if (n_vertices > 3)
40195  {
40196  unrefinement_applied =
40197  unrefine_shared_boundary_constrained_by_target_area(
40198  shd_bnd_id, chunk, polyline_vertices, polyline_target_area);
40199  }
40200 
40201  // Apply refinement
40202  bool refinement_applied =
40203  refine_shared_boundary_constrained_by_target_area(polyline_vertices,
40204  polyline_target_area);
40205 
40206  // Was unrefinement/refinement applied
40207  update_was_performed |= (unrefinement_applied || refinement_applied);
40208 
40209  // ------------------------------------------------------------------
40210  // Update the polyline representation of the shared boundary
40211 
40212  // The new shared polyline representation
40213  TriangleMeshPolyLine *new_polyline_pt =
40214  new TriangleMeshPolyLine(polyline_vertices, shd_bnd_id);
40215 
40216  // Get the curve section representation
40217  TriangleMeshCurveSection *curve_section_pt = vector_polyline_pt[pp];
40218 
40219  // Copy the connection information from the old shared polyline to
40220  // the new one
40221  this->copy_connection_information(curve_section_pt, new_polyline_pt);
40222 
40223  // Now update the polyline according to the new vertices but first
40224  // check if the object is allowed to delete the representation or
40225  // if it should be done by other object
40226  bool delete_it_on_destructor = false;
40227 
40228  // Establish the element as being deleted by the destructor of the
40229  // class
40230  std::set<TriangleMeshCurveSection*>::iterator it =
40231  this->Free_curve_section_pt.find(curve_section_pt);
40232 
40233  if (it!=this->Free_curve_section_pt.end())
40234  {
40235  this->Free_curve_section_pt.erase(it);
40236  delete curve_section_pt;
40237  delete_it_on_destructor = true;
40238  }
40239 
40240  // Copy the new representation to the output vector_polyline_pt
40241  vector_polyline_pt[pp] = new_polyline_pt;
40242 
40243  // Get the new curve section representation
40244  TriangleMeshCurveSection *new_curve_section_pt = vector_polyline_pt[pp];
40245 
40246  // Update the Boundary - Polyline map
40247  this->Boundary_curve_section_pt[shd_bnd_id] = new_curve_section_pt;
40248 
40249  if (delete_it_on_destructor)
40250  {
40251  this->Free_curve_section_pt.insert(new_curve_section_pt);
40252  }
40253 
40254  } // for (pp < npoly)
40255 
40256  return update_was_performed;
40257 
40258 }
40259 #endif // #ifdef OOMPH_HAS_MPI
40260 
40261  //=========================================================================
40262  /// \short Helper function that performs the unrefinement process
40263  /// on the specified boundary by using the provided vertices
40264  /// representation and the associated target area.
40265  //=========================================================================
40266  template<class ELEMENT>
40269  const unsigned &c,
40271  &vector_bnd_vertices,
40272  double &unrefinement_tolerance,
40273  Vector<double> &area_constraint)
40274  {
40275  // Store the vertices not allowed for deletion
40276  std::set<Vector<double> > no_delete_vertex;
40277 
40278  // Does the boundary receives connections?
40279  const bool boundary_receive_connections =
40280  this->boundary_connections(b, c, no_delete_vertex);
40281 
40282  // Boolean that indicates whether an actual update of the vertex
40283  // coordinates was performed
40284  bool unrefinement_applied = false;
40285 
40286  // Return inmedately
40287  if (!Do_boundary_unrefinement_constrained_by_target_areas)
40288  {
40289  return unrefinement_applied;
40290  }
40291 
40292  // Strategy to delete nodes: Consider the target area of the
40293  // elements (e_i and e_(i+1)) sharing the i-th node (middle node),
40294  // if the number of segments to be added is equal to zero for both
40295  // elements then compute the average of both target areas and check
40296  // if the number of segments is still zero, if that holds mark the
40297  // node to be deleted. Before delete the node check whether it is in
40298  // the non_delete_vertex list. Skip the i+1-th node and go for the
40299  // (i+2)-th one, it means, increase the counter for current node by
40300  // two.
40301 
40302  // Number of vertices on the boundary
40303  unsigned n_vertex = vector_bnd_vertices.size();
40304 
40305  // Compute a constant value
40306  const double constant_value = 4.0/sqrt(3.0);
40307 
40308  if (n_vertex > 2)
40309  {
40310  // Go through all the vertices and delete points when the target area
40311  // indicates zero points along the boundary
40312  for (unsigned i = 1; i < n_vertex-1; i+=2)
40313  {
40314  if (area_constraint[i-1] > 0 && area_constraint[i] > 0)
40315  {
40316  const double local_zeta_first = vector_bnd_vertices[i-1][0];
40317  const double local_zeta_last = vector_bnd_vertices[i+1][0];
40318  const double local_length_zeta =
40319  std::fabs(local_zeta_last-local_zeta_first);
40320 
40321  const double x1 = vector_bnd_vertices[i-1][1];
40322  const double y1 = vector_bnd_vertices[i-1][2];
40323  const double x2 = vector_bnd_vertices[i+1][1];
40324  const double y2 = vector_bnd_vertices[i+1][2];
40325  const double local_length =
40326  sqrt(((x1-x2)*(x1-x2)) + ((y1-y2)*(y1-y2)));
40327 
40328  const double x_m = vector_bnd_vertices[i][1];
40329  const double y_m = vector_bnd_vertices[i][2];
40330 
40331  const double average_area_constraint =
40332  (area_constraint[i-1] + area_constraint[i]) / 2.0;
40333 
40334  // Compute the length of the the side of an equilateral
40335  // triangle
40336  const double length_side =
40337  sqrt(constant_value*average_area_constraint);
40338 
40339  const double length_side_zeta =
40340  (local_length_zeta * length_side) / local_length;
40341 
40342  // Is the new length greater that the old one
40343  if ((length_side_zeta / local_length_zeta) > 1.0)
40344  {
40345  // If the number of segments is zero then verify the condition for
40346  // deletion of nodes but using the condition in the default
40347  // unrefine_boundary() method. If both conditions are true then
40348  // delete the node
40349  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
40350  double a_x=vector_bnd_vertices[i-1][1];
40351  double a_y=vector_bnd_vertices[i-1][2];
40352  double b_x=vector_bnd_vertices[i][1];
40353  double b_y=vector_bnd_vertices[i][2];
40354  double c_x=vector_bnd_vertices[i+1][1];
40355  double c_y=vector_bnd_vertices[i+1][2];
40356 
40357  double a=b_x-a_x;
40358  double b=b_y-a_y;
40359  double c=c_x-a_x;
40360  double d=c_y-a_y;
40361 
40362  double e=a*(a_x+b_x)+b*(a_y+b_y);
40363  double f=c*(a_x+c_x)+d*(a_y+c_y);
40364 
40365  double g=2.0*(a*(c_y-b_y)-b*(c_x-b_x));
40366 
40367  bool do_it=false;
40368  if (std::fabs(g)<1.0e-14)
40369  {
40370  do_it=true;
40371  }
40372  else
40373  {
40374  double p_x=(d*e-b*f)/g;
40375  double p_y=(a*f-c*e)/g;
40376 
40377  double r=sqrt(pow((a_x-p_x),2)+pow((a_y-p_y),2));
40378 
40379  double rhalfca_x=0.5*(a_x-c_x);
40380  double rhalfca_y=0.5*(a_y-c_y);
40381 
40382  double halfca_squared=pow(rhalfca_x,2)+pow(rhalfca_y,2);
40383 
40384  double sticky_out_bit=r-sqrt(std::fabs((r*r) - halfca_squared));
40385 
40386  // If sticky out bit divided by distance between end nodes
40387  // is less than tolerance the boundary is so flat that we
40388  // can safely kill the node
40389  if ((sticky_out_bit/(2.0*sqrt(halfca_squared)))<
40390  unrefinement_tolerance)
40391  {
40392  do_it=true;
40393  }
40394  }
40395 
40396  // If the vertex was proposed for deletion check if it is
40397  // allowed for being deleted
40398  if (do_it && boundary_receive_connections)
40399  {
40400  // Is the vertex one of the non deletable vertices
40401  for (std::set<Vector<double> >::iterator it =
40402  no_delete_vertex.begin();
40403  it != no_delete_vertex.end(); it++)
40404  {
40405  // Compute the distance between the proposed node to
40406  // delete and the ones that should not be deleted
40407  const double x = (*it)[0];
40408  const double y = (*it)[1];
40409  double error = (x_m - x)*(x_m - x) + (y_m - y)*(y_m - y);
40410  error = sqrt(error);
40411 
40412  if(error <
40414  {
40415  // Do not delete the vertex
40416  do_it = false;
40417  break;
40418  }
40419 
40420  }
40421 
40422  } // if (do_it && boundary_receive_connections)
40423 
40424  // Remove node?
40425  if (do_it)
40426  {
40427  vector_bnd_vertices[i].resize(0);
40428  }
40429  } // if (n_seg == 0)
40430  } // if (area_constraint[i] >= 0)
40431  } // for (i < n_vertex-1)
40432 
40433  // Create a new (temporary) vector for the nodes, so that deleted nodes
40434  // are not stored
40435  Vector<Vector<double> > compact_vector;
40436 
40437  // Compact vector for target areas too
40438  Vector<double> compact_area_constraint;
40439 
40440  // Copy only the non deleted nodes
40441  for(unsigned i = 0; i < n_vertex; i++)
40442  {
40443  // If the entry was not deleted include it in the new vector
40444  if (vector_bnd_vertices[i].size()!=0)
40445  {
40446  compact_vector.push_back(vector_bnd_vertices[i]);
40447  }
40448  }
40449 
40450  // ------------------------------------------------------------------
40451  // Size of the target areas vector
40452  unsigned nsize_target = area_constraint.size();
40453  if (nsize_target == 1)
40454  {
40455  // No node was deleted, just copy the target area
40456  compact_area_constraint.push_back(area_constraint[0]);
40457  }
40458 
40459  // Copy the target areas
40460  for(unsigned i = 1; i < n_vertex; i+=2)
40461  {
40462  // If the entry was not deleted include the target areas of both
40463  // elements sharing the node
40464  if (vector_bnd_vertices[i].size()!=0)
40465  {
40466  compact_area_constraint.push_back(area_constraint[i-1]);
40467  // To catch the case when working with even number of vertex
40468  if (i < nsize_target)
40469  {
40470  compact_area_constraint.push_back(area_constraint[i]);
40471  }
40472  }
40473  else
40474  {
40475  // If the node was deleted then compute the new target area as the
40476  // average of the target area of the elements sharing the node
40477  double new_area_constraint =
40478  (area_constraint[i-1] + area_constraint[i]) / 2.0;
40479  compact_area_constraint.push_back(new_area_constraint);
40480  }
40481  }
40482 
40483  // If the size of the compact vector is different from the size of the
40484  // vector before applying the area length constraint then the polyline
40485  // was updated
40486  if( n_vertex != compact_vector.size() )
40487  {
40488  unrefinement_applied = true;
40489  }
40490 
40491  // Copy back to the original vector
40492  n_vertex = compact_vector.size();
40493  vector_bnd_vertices.resize(n_vertex);
40494  for(unsigned i = 0; i < n_vertex; i++)
40495  {
40496  vector_bnd_vertices[i].resize(3);
40497  vector_bnd_vertices[i][0] = compact_vector[i][0];
40498  vector_bnd_vertices[i][1] = compact_vector[i][1];
40499  vector_bnd_vertices[i][2] = compact_vector[i][2];
40500  }
40501 
40502  // Copy back to the original vector of target areas
40503  unsigned ntarget_areas = compact_area_constraint.size();
40504  area_constraint.resize(ntarget_areas);
40505  for(unsigned i = 0; i < ntarget_areas; i++)
40506  {
40507  area_constraint[i] = compact_area_constraint[i];
40508  }
40509 
40510  } // if (n_vertex > 2)
40511 
40512  return unrefinement_applied;
40513 
40514  }
40515 
40516  //=========================================================================
40517  /// \short Helper function that performs the refinement process
40518  /// on the specified boundary by using the provided vertices
40519  /// representation and the associated elements target area.
40520  //=========================================================================
40521  template<class ELEMENT>
40524  mesh_geom_obj_pt,
40526  &vector_bnd_vertices,
40527  double &refinement_tolerance,
40528  Vector<double> &area_constraint)
40529  {
40530  // Boolean that indicates whether an actual update of the vertex
40531  // coordinates was performed
40532  bool refinement_applied = false;
40533 
40534  // Return inmedately
40535  if (!Do_boundary_refinement_constrained_by_target_areas)
40536  {
40537  return refinement_applied;
40538  }
40539 
40540  // Get the total number of current vertices
40541  unsigned n_vertex=vector_bnd_vertices.size();
40542 
40543  // Compute a constant value
40544  const double constant_value = 4.0/sqrt(3.0);
40545 
40546  if (n_vertex > 1)
40547  {
40548  // Create a new (temporary) vector for the nodes, so that new
40549  // nodes can be stored
40550  Vector<Vector<double> > new_vector;
40551 
40552  // Go through all the vertices and create points according to the
40553  // specified element area
40554  for (unsigned i = 0; i < n_vertex-1; i++)
40555  {
40556  // Include the first node
40557  new_vector.push_back(vector_bnd_vertices[i]);
40558 
40559  if (area_constraint[i] > 0)
40560  {
40561  double local_zeta_first = vector_bnd_vertices[i][0];
40562  double local_zeta_last = vector_bnd_vertices[i+1][0];
40563  const double local_length_zeta =
40564  std::fabs(local_zeta_last-local_zeta_first);
40565 
40566  // Check if need to interchange the zeta first and the zeta
40567  // last (to ensure the same order in zeta values in any two
40568  // processors)
40569  if (local_zeta_first > local_zeta_last)
40570  {
40571  const double tmp_zeta = local_zeta_first;
40572  local_zeta_first = local_zeta_last;
40573  local_zeta_last = tmp_zeta;
40574  }
40575 
40576  const double x1 = vector_bnd_vertices[i][1];
40577  const double y1 = vector_bnd_vertices[i][2];
40578  const double x2 = vector_bnd_vertices[i+1][1];
40579  const double y2 = vector_bnd_vertices[i+1][2];
40580  const double local_length =
40581  sqrt(((x1-x2)*(x1-x2)) + ((y1-y2)*(y1-y2)));
40582 
40583  // Compute the length in zeta units
40584  const double length_side = sqrt(constant_value*area_constraint[i]);
40585  const double length_side_zeta =
40586  (local_length_zeta * length_side) / local_length;
40587 
40588  // How many segments should be introduced
40589  const double n_seg_double = length_side_zeta/local_length_zeta;
40590 
40591  // One segment initialy (the original one)
40592  unsigned n_seg = 1;
40593 
40594  // How many more segments to introduce?
40595  n_seg+=static_cast<unsigned>(std::floor(1.0/n_seg_double));
40596 
40597  // Are there segments to introduce? There must be at least one
40598  // segment, the original one
40599  if (n_seg > 0)
40600  {
40601  // The zeta increment
40602  double zeta_increment = (local_length_zeta)/((double)n_seg);
40603 
40604  Vector<double> zeta(1);
40605  // Create the n_seg segmets between each pair of nodes
40606  for(unsigned s=1;s<n_seg;s++)
40607  {
40608  // Get the coordinates
40609  zeta[0]= local_zeta_first + zeta_increment*double(s);
40610  Vector<double> vertex(2);
40611  mesh_geom_obj_pt->position(zeta, vertex);
40612 
40613  // Create the new node
40614  Vector<double> new_node(3);
40615  new_node[0]=zeta[0];
40616  new_node[1]=vertex[0];
40617  new_node[2]=vertex[1];
40618 
40619  // Include the new node
40620  new_vector.push_back(new_node);
40621 
40622  } // for (s<=n_seg)
40623 
40624  } // if (n_seg > 0)
40625 
40626  } // if (area_constraint[i] >= 0)
40627 
40628  } // for (i < n_vertex-1)
40629 
40630  // Once finished all the vertices add the last node to the vector
40631  new_vector.push_back(vector_bnd_vertices[n_vertex-1]);
40632 
40633  // If the new size of the vector (including the added nodes) is
40634  // different from the size of the vector before applying the
40635  // area length constraint then the polyline was updated
40636  n_vertex=new_vector.size();
40637  if( n_vertex != vector_bnd_vertices.size() )
40638  {
40639  refinement_applied = true;
40640  }
40641 
40642  // Copy the new representation
40643  vector_bnd_vertices.resize(n_vertex);
40644  for(unsigned i=0;i<n_vertex;i++)
40645  {
40646  vector_bnd_vertices[i].resize(3);
40647  vector_bnd_vertices[i][0]=new_vector[i][0];
40648  vector_bnd_vertices[i][1]=new_vector[i][1];
40649  vector_bnd_vertices[i][2]=new_vector[i][2];
40650  }
40651 
40652  } // if (n_vertex > 1)
40653 
40654  return refinement_applied;
40655 
40656  }
40657 
40658  //======================================================================
40659  /// \short Helper function that performs the unrefinement process
40660  /// on the specified boundary by using the provided vertices
40661  /// representation and the associated target area.
40662  /// NOTE: This is the version that applies unrefinement to shared
40663  /// boundaries
40664  //======================================================================
40665  template <class ELEMENT>
40668  const unsigned &b,
40669  const unsigned &c,
40670  Vector<Vector<double> > &vector_bnd_vertices,
40671  Vector<double> &area_constraint)
40672  {
40673  // Store the vertices not allowed for deletion
40674  std::set<Vector<double> > no_delete_vertex;
40675 
40676  // Does the boundary receives connections?
40677  const bool boundary_receive_connections =
40678  this->boundary_connections(b, c, no_delete_vertex);
40679 
40680  // Boolean that indicates whether an actual update of the vertex
40681  // coordinates was performed
40682  bool unrefinement_applied = false;
40683 
40684  // Return inmedately
40685  if (!Do_shared_boundary_unrefinement_constrained_by_target_areas)
40686  {
40687  return unrefinement_applied;
40688  }
40689 
40690  // Strategy to delete nodes:
40691 
40692  // Strategy to delete nodes: Consider the target area of the
40693  // elements (e_i and e_(i+1)) sharing the i-th node (middle node),
40694  // if the number of segments to be added is equal to zero for both
40695  // elements then compute the average of both target areas and check
40696  // if the number of segments is still zero, if that holds mark the
40697  // node to be deleted. Before delete the node check whether it is in
40698  // the non_delete_vertex list. Skip the i+1-th node and go for the
40699  // (i+2)-th one, it means, increase the counter for current node by
40700  // two.
40701 
40702  // Number of vertices on the boundary
40703  unsigned n_vertex = vector_bnd_vertices.size();
40704 
40705  // Compute a constant value
40706  const double constant_value = 4.0/sqrt(3.0);
40707 
40708  if (n_vertex > 2)
40709  {
40710  // Go through all the vertices and delete points when the target
40711  // area indicates zero points along the boundary
40712  for (unsigned i = 1; i < n_vertex-1; i+=2)
40713  {
40714  // Is a target area assigned to the left and right element of
40715  // the i-th node
40716  if (area_constraint[i-1] > 0 && area_constraint[i] > 0)
40717  {
40718  // Get the vertices to the left
40719  const double x1 = vector_bnd_vertices[i-1][0];
40720  const double y1 = vector_bnd_vertices[i-1][1];
40721  // ... and to the right of the i-th vertex
40722  const double x2 = vector_bnd_vertices[i+1][0];
40723  const double y2 = vector_bnd_vertices[i+1][1];
40724 
40725  // The distance
40726  const double local_length =
40727  sqrt(((x1-x2)*(x1-x2)) + ((y1-y2)*(y1-y2)));
40728 
40729  // Get the middle vertex
40730  const double x_m = vector_bnd_vertices[i][0];
40731  const double y_m = vector_bnd_vertices[i][1];
40732 
40733  // The average area
40734  const double average_area_constraint =
40735  (area_constraint[i-1] + area_constraint[i]) / 2.0;
40736 
40737  // Compute the base length of the triangle with
40738  // area_constraint area
40739  const double length_side =
40740  sqrt(constant_value*average_area_constraint);
40741 
40742  // Is the new length greater than the old one
40743  if ((length_side / local_length) > 1.0)
40744  {
40745  bool do_it=true;
40746 
40747  // If the vertex was proposed for deletion check that it is
40748  // allowed for being deleted
40749  if (do_it && boundary_receive_connections)
40750  {
40751  // Is the vertex one of the non deletable vertices
40752  for (std::set<Vector<double> >::iterator it =
40753  no_delete_vertex.begin();
40754  it != no_delete_vertex.end(); it++)
40755  {
40756  // Compute the distance between the proposed node to delete
40757  // and the ones that should not be deleted
40758  const double x = (*it)[0];
40759  const double y = (*it)[1];
40760  double error = (x_m - x)*(x_m - x) + (y_m - y)*(y_m - y);
40761  error = sqrt(error);
40762 
40763  if(error <
40765  {
40766  // Do not delete the vertex
40767  do_it = false;
40768  break;
40769  }
40770 
40771  }
40772 
40773  } // if (do_it && boundary_receive_connections)
40774 
40775  // Remove node?
40776  if (do_it)
40777  {
40778  vector_bnd_vertices[i].resize(0);
40779  }
40780  } // if ((local_length / length_side) <= 1.3)
40781 
40782  } // if (area_constraint[i] >= 0)
40783 
40784  } // for (i < n_vertex-1)
40785 
40786  // Create a new (temporary) vector for the nodes, so that deleted nodes
40787  // are not stored
40788  Vector<Vector<double> > compact_vector;
40789 
40790  // Compact vector for target areas too
40791  Vector<double> compact_area_constraint;
40792 
40793  // Copy only the non deleted nodes
40794  for(unsigned i = 0; i < n_vertex; i++)
40795  {
40796  // If the entry was not deleted include it in the new vector
40797  if (vector_bnd_vertices[i].size()!=0)
40798  {
40799  compact_vector.push_back(vector_bnd_vertices[i]);
40800  }
40801  }
40802 
40803  // ------------------------------------------------------------------
40804  // The number of target areas
40805  unsigned n_area_constraint = area_constraint.size();
40806  if (n_area_constraint == 1)
40807  {
40808  // No node could be deleted then just copy the target area
40809  compact_area_constraint.push_back(area_constraint[0]);
40810  }
40811 
40812  // Copy the target areas
40813  for(unsigned i = 1; i < n_vertex; i+=2)
40814  {
40815  // If the entry was not deleted include the target areas of both
40816  // elements sharing the node
40817  if (vector_bnd_vertices[i].size()!=0)
40818  {
40819  compact_area_constraint.push_back(area_constraint[i-1]);
40820  // To catch the case when working with even number of vertices
40821  if (i < n_area_constraint)
40822  {
40823  compact_area_constraint.push_back(area_constraint[i]);
40824  }
40825  }
40826  else
40827  {
40828  // If the node was deleted then compute the new target area as the
40829  // average of the target area of the elements sharing the node
40830  const double new_area_constraint =
40831  (area_constraint[i-1] + area_constraint[i]) / 2.0;
40832  compact_area_constraint.push_back(new_area_constraint);
40833  }
40834  } // for (i < n_vertex)
40835 
40836  // If the size of the compact vector is different from the size of
40837  // the vector before applying the area length constraint then the
40838  // polyline was updated
40839  if( n_vertex != compact_vector.size() )
40840  {
40841  unrefinement_applied = true;
40842  }
40843 
40844  // Copy back to the original vector
40845  n_vertex = compact_vector.size();
40846  vector_bnd_vertices.resize(n_vertex);
40847  for(unsigned i = 0; i < n_vertex; i++)
40848  {
40849  vector_bnd_vertices[i].resize(2);
40850  vector_bnd_vertices[i][0] = compact_vector[i][0];
40851  vector_bnd_vertices[i][1] = compact_vector[i][1];
40852  }
40853 
40854  // Copy back to the original vector of target areas
40855  unsigned ntarget_areas = compact_area_constraint.size();
40856  area_constraint.resize(ntarget_areas);
40857  for(unsigned i = 0; i < ntarget_areas; i++)
40858  {
40859  area_constraint[i] = compact_area_constraint[i];
40860  }
40861 
40862  } // if (n_vertex > 2)
40863 
40864  return unrefinement_applied;
40865 
40866  }
40867 
40868  //======================================================================
40869  /// \short Helper function that performs the refinement process
40870  /// on the specified boundary by using the provided vertices
40871  /// representation and the associated elements target area.
40872  /// NOTE: This is the version that applies refinement to shared
40873  /// boundaries
40874  //======================================================================
40875  template <class ELEMENT>
40878  Vector<Vector<double> > &vector_bnd_vertices,
40879  Vector<double> &area_constraint)
40880  {
40881  // Boolean that indicates whether an actual update of the vertex
40882  // coordinates was performed
40883  bool refinement_applied = false;
40884 
40885  // Return inmedately
40886  if (!Do_shared_boundary_refinement_constrained_by_target_areas)
40887  {
40888  return refinement_applied;
40889  }
40890 
40891  // Get the number of segments
40892  unsigned nsegments = vector_bnd_vertices.size() - 1;
40893 
40894  // Create a new (temporary) vector for the nodes, so that new nodes
40895  // can be stored
40896  Vector<Vector<double> > tmp_bnd_vertices;
40897 
40898  // Compute a constant value
40899  const double constant_value = 4.0/sqrt(3.0);
40900 
40901  for (unsigned s = 0; s < nsegments; s++)
40902  {
40903  Vector<double> left_vertex = vector_bnd_vertices[s];
40904  Vector<double> right_vertex = vector_bnd_vertices[s+1];
40905 
40906  // Initial and final point of the segment
40907  const double x1 = left_vertex[0];
40908  const double y1 = left_vertex[1];
40909  const double x2 = right_vertex[0];
40910  const double y2 = right_vertex[1];
40911 
40912  // Lenght of the segment
40913  const double segment_length =
40914  sqrt(((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2)));
40915 
40916  // Compute the distance for the new segments
40917  const double new_segment_length =
40918  sqrt(constant_value*area_constraint[s]);
40919 
40920  // How many segments should be introduced
40921  const double n_seg_double = new_segment_length / segment_length;
40922 
40923  // One segment initialy (the original one)
40924  unsigned nseg = 1;
40925  // How many more segments to introduce?
40926  nseg+=static_cast<unsigned>(std::floor(1.0/n_seg_double));
40927 
40928  // The left vertex must be always included, even though no new vertex
40929  // be added
40930  tmp_bnd_vertices.push_back(left_vertex);
40931 
40932  // Are there segments to introduce? There must be at least one
40933  // segment, the original one
40934  if (nseg > 0)
40935  {
40936  // Create intermediate vertices
40937  double incrementx = (right_vertex[0] - left_vertex[0])/(double)(nseg);
40938  double incrementy = (right_vertex[1] - left_vertex[1])/(double)(nseg);
40939  for (unsigned i = 1; i < nseg; i++)
40940  {
40941  Vector<double> tmp_vertex(2);
40942  tmp_vertex[0] = left_vertex[0] + incrementx*i;
40943  tmp_vertex[1] = left_vertex[1] + incrementy*i;
40944  tmp_bnd_vertices.push_back(tmp_vertex);
40945  } // for (i < nseg)
40946 
40947  } // if (nseg > 0)
40948 
40949  } // for (s < nsegments)
40950 
40951  // Add the last vertex
40952  tmp_bnd_vertices.push_back(vector_bnd_vertices[nsegments]);
40953 
40954  // If the new size of the vector (including the added nodes) is
40955  // different from the size of the vector before applying the
40956  // refinement then the polyline was updated
40957  nsegments = tmp_bnd_vertices.size() - 1;
40958  if( nsegments != vector_bnd_vertices.size() - 1 )
40959  {
40960  refinement_applied = true;
40961 
40962  // Copy across
40963  vector_bnd_vertices.resize(nsegments + 1);
40964  for(unsigned i = 0; i < nsegments + 1; i++)
40965  {
40966  vector_bnd_vertices[i].resize(2);
40967  vector_bnd_vertices[i][0] = tmp_bnd_vertices[i][0];
40968  vector_bnd_vertices[i][1] = tmp_bnd_vertices[i][1];
40969  }
40970  }
40971 
40972  return refinement_applied;
40973 
40974  }
40975 
40976 //======================================================================
40977 /// \short Updates the polylines representation after restart
40978 //======================================================================
40979 template <class ELEMENT>
40982 {
40983 
40984  // **********************************************************************
40985  // 1) Collect the elements adjacet to the polyline boundary id and
40986  // update the polyline
40987  // **********************************************************************
40988 
40989  // (1.1) Get the face mesh representation
40990  Vector<Mesh*> face_mesh_pt;
40991  get_face_mesh_representation(polygon_pt,face_mesh_pt);
40992 
40993  // (1.2) Create vertices of the polylines by using the vertices of the
40994  // FaceElements
40995  Vector<double> vertex_coord(3); // zeta,x,y
40996  Vector<double> bound_left(1);
40997  Vector<double> bound_right(1);
40998 
40999  const unsigned n_polyline = polygon_pt->npolyline();
41000 
41001  // Go for each polyline
41002  for(unsigned p=0;p<n_polyline;p++)
41003  {
41004  // Get the MeshAsGeomObject representation just once per polyline,
41005  // this object is only used by the
41006  // refine_boundary_constrained_by_target_area() method. We get it here
41007  // to ensure that all processors (in a distributed context) get this
41008  // representation just once, and because an AllToAll MPI communication
41009  // is used in this calling
41010  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt[p]);
41011 
41012  // Set of coordinates that are on the boundary
41013  // Set entries are ordered on first entry in vector which stores
41014  // the boundary coordinate so the vertices come out in order!
41015  std::set<Vector<double> > vertex_nodes;
41016 
41017  // Vector to store the vertices, transfer the sorted vertices from the
41018  // set to this vector, --- including the z-value ---
41019  Vector<Vector<double> > tmp_vector_vertex_node;
41020 
41021  // Vector to store the coordinates of the polylines, same as the
41022  // tmp_vector_vertex_node vector (after adding more nodes) but
41023  // --- without the z-value ---, used to re-generate the polylines
41024  Vector<Vector<double> > vector_vertex_node;
41025 
41026 #ifdef OOMPH_HAS_MPI
41027  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
41028  // Set of coordinates that are on the boundary (splitted boundary version)
41029  // The first vector is used to allocate the points for each sub-boundary
41030  // Set entries are ordered on first entry in vector which stores
41031  // the boundary coordinate so the vertices come out in order!
41032  Vector<std::set<Vector<double> > >sub_vertex_nodes;
41033 
41034  // Vector to store the vertices, transfer the sorted vertices from the
41035  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
41036  Vector<Vector<Vector<double> > >sub_tmp_vector_vertex_node;
41037 
41038  // Vector to store the coordinates of the polylines that will represent
41039  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
41040  // but --- without the z-value ---, used to generate the sub-polylines
41041  Vector<Vector<Vector<double> > > sub_vector_vertex_node;
41042  // --------- Stuff to deal with splitted boundaries ----------- End ------
41043 #endif
41044 
41045  //Get the boundary id
41046  unsigned bound=polygon_pt->curve_section_pt(p)->boundary_id();
41047 
41048  /// Use a vector of vector for vertices and target areas to
41049  /// deal with the cases when the boundaries are split by the
41050  /// distribution process
41051 
41052  // Loop over the face elements (ordered) and add their vertices
41053  const unsigned nface_element = face_mesh_pt[p]->nelement();
41054 
41055  // Store the non halo face elements, the ones from which we will
41056  // get the vertices
41057  Vector<FiniteElement*> non_halo_face_element_pt;
41058  // Map to store the index of the face element on a boundary
41059  std::map<FiniteElement*,unsigned> face_element_index_on_boundary;
41060 
41061  for(unsigned ef=0;ef<nface_element;++ef)
41062  {
41063  FiniteElement* ele_face_pt = face_mesh_pt[p]->finite_element_pt(ef);
41064  // Skip the halo elements
41065 #ifdef OOMPH_HAS_MPI
41066  if (this->is_mesh_distributed())
41067  {
41068  // Only work with non-halo elements
41069  if (ele_face_pt->is_halo()) {continue;}
41070  }
41071 #endif
41072  // Add the face element to the vector
41073  non_halo_face_element_pt.push_back(ele_face_pt);
41074  face_element_index_on_boundary[ele_face_pt] = ef;
41075  }
41076 
41077  // Get the number of non halo face element
41078  const unsigned nnon_halo_face_element = non_halo_face_element_pt.size();
41079 
41080  // Map to know the already sorted face elements
41081  std::map<FiniteElement*,bool> face_element_done;
41082 
41083  // Number of done face elements
41084  unsigned nsorted_face_elements = 0;
41085 
41086 #ifdef OOMPH_HAS_MPI
41087  // Counter for sub_boundaries
41088  unsigned nsub_boundaries = 0;
41089 #endif // #ifdef OOMPH_HAS_MPI
41090 
41091  // Continue until all the face elements have been sorted
41092  // This while is to deal with the cases of splitted boundaries
41093  while(nsorted_face_elements < nnon_halo_face_element)
41094  {
41095  // Get and initial face element
41096  FiniteElement* ele_face_pt = 0;
41097 #ifdef PARANOID
41098  bool found_initial_face_element = false;
41099 #endif
41100 
41101  unsigned iface = 0;
41102  for (iface = 0; iface < nnon_halo_face_element; iface++)
41103  {
41104  ele_face_pt = non_halo_face_element_pt[iface];
41105  // If not done then take it as initial face element
41106  if (!face_element_done[ele_face_pt])
41107  {
41108 #ifdef PARANOID
41109  found_initial_face_element = true;
41110 #endif
41111  nsorted_face_elements++;
41112  iface++;
41113  break;
41114  }
41115  }
41116 
41117 #ifdef PARANOID
41118  if (!found_initial_face_element)
41119  {
41120  std::ostringstream error_message;
41121  error_message
41122  <<"Could not find an initial face element for the current segment\n";
41123  // << "----- Possible memory leak -----\n";
41124  throw OomphLibError(error_message.str(),
41125  "RefineableTriangleMesh::update_polygon_after_restart()",
41126  OOMPH_EXCEPTION_LOCATION);
41127  }
41128 #endif
41129 
41130  // Local set of coordinates that are on the boundary
41131  // Set entries are ordered on first entry in vector which stores
41132  // the boundary coordinate so the vertices come out in order!
41133  std::set<Vector<double> > local_vertex_nodes;
41134 
41135  // Vector to store the vertices, transfer the sorted vertices from the
41136  // set (local) to this vector (local), --- including the z-value ---
41137  Vector<Vector<double> > local_tmp_vector_vertex_node;
41138 
41139  // ------------------------------------------------------------------
41140  // ------------------------------------------------------------------
41141  // -----------------------------------------------------------------
41142  // Add the vertices of the initial face element to the set of local
41143  // sorted vertices
41144  // -----------------------------------------------------------------
41145  unsigned nnode = ele_face_pt->nnode();
41146  // Add the left-hand node to the set:
41147  // Boundary coordinate
41148  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
41149  vertex_coord[0] = bound_left[0];
41150 
41151  // Actual coordinates
41152  for(unsigned i=0;i<2;i++)
41153  {
41154  vertex_coord[i+1] = ele_face_pt->node_pt(0)->x(i);
41155  }
41156  local_vertex_nodes.insert(vertex_coord);
41157 
41158  // Add the right-hand nodes to the set:
41159  // Boundary coordinate
41160  ele_face_pt->node_pt(nnode-1)->
41161  get_coordinates_on_boundary(bound,bound_right);
41162  vertex_coord[0] = bound_right[0];
41163 
41164  // Actual coordinates
41165  for(unsigned i=0;i<2;i++)
41166  {
41167  vertex_coord[i+1] = ele_face_pt->node_pt(nnode-1)->x(i);
41168  }
41169  local_vertex_nodes.insert(vertex_coord);
41170 
41171  // The initial and final node on the set
41172  Node *first_node_pt = ele_face_pt->node_pt(0);
41173  Node *last_node_pt = ele_face_pt->node_pt(nnode-1);
41174 
41175  // Mark the current face element as done
41176  face_element_done[ele_face_pt] = true;
41177 
41178  // ------------------------------------------------------------------
41179  // ------------------------------------------------------------------
41180  // ------------------------------------------------------------------
41181 
41182  // Continue iterating if a new face element has been added to the
41183  // list
41184  bool face_element_added = false;
41185 
41186  // While a new face element has been added to the set of sorted
41187  // face elements then re-iterate
41188  do
41189  {
41190  // Start from the next face elements since we have already added
41191  // the previous one as the initial face element (any previous face
41192  // element had to be added on previous iterations)
41193  for (unsigned iiface=iface;iiface<nnon_halo_face_element;iiface++)
41194  {
41195  face_element_added = false;
41196  ele_face_pt = non_halo_face_element_pt[iiface];
41197  if (!face_element_done[ele_face_pt])
41198  {
41199  // Get each individual node to check if they are contiguous
41200  nnode = ele_face_pt->nnode();
41201  Node* left_node_pt = ele_face_pt->node_pt(0);
41202  Node* right_node_pt = ele_face_pt->node_pt(nnode-1);
41203 
41204  if (left_node_pt == first_node_pt)
41205  {
41206  first_node_pt = right_node_pt;
41207  face_element_added = true;
41208  }
41209  else if (left_node_pt == last_node_pt)
41210  {
41211  last_node_pt = right_node_pt;
41212  face_element_added = true;
41213  }
41214  else if (right_node_pt == first_node_pt)
41215  {
41216  first_node_pt = left_node_pt;
41217  face_element_added = true;
41218  }
41219  else if (right_node_pt == last_node_pt)
41220  {
41221  last_node_pt = left_node_pt;
41222  face_element_added = true;
41223  }
41224 
41225  if (face_element_added)
41226  {
41227  // Add the left-hand node to the set:
41228  // Boundary coordinate
41229  left_node_pt->get_coordinates_on_boundary(bound,bound_left);
41230  vertex_coord[0] = bound_left[0];
41231 
41232  // Actual coordinates
41233  for(unsigned i=0;i<2;i++)
41234  {
41235  vertex_coord[i+1] = left_node_pt->x(i);
41236  }
41237  local_vertex_nodes.insert(vertex_coord);
41238 
41239  // Add the right-hand nodes to the set:
41240  // Boundary coordinate
41241  right_node_pt->get_coordinates_on_boundary(bound,bound_right);
41242  vertex_coord[0] = bound_right[0];
41243 
41244  // Actual coordinates
41245  for(unsigned i=0;i<2;i++)
41246  {
41247  vertex_coord[i+1] = right_node_pt->x(i);
41248  }
41249  local_vertex_nodes.insert(vertex_coord);
41250 
41251  // Mark as done only if one of its nodes has been
41252  // added to the list
41253  face_element_done[ele_face_pt] = true;
41254  nsorted_face_elements++;
41255 
41256  break;
41257  }
41258 
41259  } // if (!edge_done[edge])
41260  } // for (iiedge < nedges)
41261  }while(face_element_added &&
41262  (nsorted_face_elements < nnon_halo_face_element));
41263 
41264  // -----------------------------------------------------------------
41265  // At this point we already have a sorted set of nodes and
41266  // can be used to peform the unrefinement and refinement procedures
41267  // -----------------------------------------------------------------
41268 
41269  // Get the number of nodes on the list
41270  const unsigned nlocal_nodes = local_vertex_nodes.size();
41271  // Change representation to vector for easy of handling ...
41272  local_tmp_vector_vertex_node.resize(nlocal_nodes);
41273 
41274  // Copy the vertices of the nodes
41275  unsigned counter = 0;
41276  std::set<Vector<double> >::iterator it_vertex;
41277  for (it_vertex = local_vertex_nodes.begin();
41278  it_vertex != local_vertex_nodes.end();
41279  it_vertex++)
41280  {
41281  local_tmp_vector_vertex_node[counter].resize(3);
41282  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
41283  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
41284  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
41285  counter++;
41286  }
41287 
41288  // *********************************************************************
41289  // 3) Create the vertices along the boundary using the target area to
41290  // define the distance among them
41291  // *********************************************************************
41292 
41293  // Clear the local containter to recover the nodes ordered using the
41294  // zeta value
41295  local_vertex_nodes.clear();
41296 
41297  // At the end of each unrefinement/refinement step store the new nodes
41298  // on the set that will give rise to the vertices of the new polyline
41299  // representation
41300  unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
41301  for (unsigned i = 0; i < nnew_nodes; i++)
41302  {
41303  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
41304  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
41305  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
41306  vertex_nodes.insert(vertex_coord); // Global container
41307  local_vertex_nodes.insert(vertex_coord);
41308  }
41309 
41310 #ifdef OOMPH_HAS_MPI
41311  if (this->is_mesh_distributed())
41312  {
41313  // Add the set of vertices for the boundary, this will help to detect
41314  // if we need to deal with sub_boundaries and sub_polylines represen.
41315  sub_vertex_nodes.push_back(local_vertex_nodes);
41316  // Increase the counter for sub_boundaries
41317  nsub_boundaries++;
41318  }
41319 #endif
41320 
41321  } // while(nsorted_face_elements < nnon_halo_face_element)
41322 
41323  // Now turn into vector for ease of handling...
41324  unsigned npoly_vertex = vertex_nodes.size();
41325  tmp_vector_vertex_node.resize(npoly_vertex);
41326  unsigned count = 0;
41327  std::set<Vector<double> >::iterator it;
41328  for(it = vertex_nodes.begin(); it!=vertex_nodes.end(); ++it)
41329  {
41330  tmp_vector_vertex_node[count].resize(3);
41331  tmp_vector_vertex_node[count][0] = (*it)[0];
41332  tmp_vector_vertex_node[count][1] = (*it)[1];
41333  tmp_vector_vertex_node[count][2] = (*it)[2];
41334  ++count;
41335  }
41336 
41337 #ifdef OOMPH_HAS_MPI
41338  // --------- Stuff for the sub_boundaries ----- Begin section ---------
41339 #ifdef PARANOID
41340  unsigned nsub_boundaries_set = sub_vertex_nodes.size();
41341  if (nsub_boundaries_set != nsub_boundaries)
41342  {
41343  std::ostringstream error_message;
41344  error_message
41345  << "The number of found sub-boundaries and the number of counted\n"
41346  << "sub-boundaries are different:\n"
41347  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
41348  << "Number of counted sub-boundaries: ("<<nsub_boundaries<<")\n";
41349  throw OomphLibError(error_message.str(),
41350  "RefineableTriangleMesh::update_polygon_after_restart()",
41351  OOMPH_EXCEPTION_LOCATION);
41352  }
41353 #endif
41354 
41355  // Verify if need to deal with sub_boundaries
41356  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41357  {
41358  // Mark the boundary as been splitted in the partition process
41359  this->Boundary_was_splitted[bound] = true;
41360  // Resize the vector to store the info. of sub-boundaries
41361  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
41362  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41363  {
41364  // Turn info. into vector for ease of handling...
41365  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
41366  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
41367  unsigned subcount = 0;
41368  std::set<Vector<double> >::iterator subit;
41369  for(subit = sub_vertex_nodes[isub].begin();
41370  subit != sub_vertex_nodes[isub].end(); ++subit)
41371  {
41372  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
41373  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
41374  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
41375  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
41376  ++subcount;
41377  }
41378  }
41379  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41380  // --------- Stuff for the sub_boundaries ----- End section ------------
41381 #endif // OOMPH_HAS_MPI
41382 
41383 
41384  // For further processing the three-dimensional vector
41385  // has to be reduced to a two-dimensional vector
41386  unsigned n_vertex=tmp_vector_vertex_node.size();
41387 
41388  // Resize the vector for vectices
41389  vector_vertex_node.resize(n_vertex);
41390  for(unsigned i=0;i<n_vertex;i++)
41391  {
41392  vector_vertex_node[i].resize(2);
41393  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
41394  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
41395  }
41396 
41397 #ifdef OOMPH_HAS_MPI
41398  // --------- Stuff for the sub_boundaries ----- Begin section ----------
41399  // Verify if need to deal with sub_boundaries
41400  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41401  {
41402  // For further processing the three-dimensional vector
41403  // has to be reduced to a two-dimensional vector
41404  // Resize the vector to store the info. of sub-boundaries
41405  sub_vector_vertex_node.resize(nsub_boundaries);
41406  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41407  {
41408  const unsigned subn_vertex =
41409  sub_tmp_vector_vertex_node[isub].size();
41410  // Resize the vector for vectices
41411  sub_vector_vertex_node[isub].resize(subn_vertex);
41412  for(unsigned i=0;i<subn_vertex;i++)
41413  {
41414  sub_vector_vertex_node[isub][i].resize(2);
41415  sub_vector_vertex_node[isub][i][0]=
41416  sub_tmp_vector_vertex_node[isub][i][1];
41417  sub_vector_vertex_node[isub][i][1]=
41418  sub_tmp_vector_vertex_node[isub][i][2];
41419  }
41420  }
41421  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41422 
41423  // We already have the info. for the sub-boundaries (if necessary)
41424  // and then we can create the sub-boundaries representations to
41425  // ease the generation of the mesh by Triangle
41426 
41427  // --------- Stuff for the sub_boundaries ----- End section ------------
41428 #endif // OOMPH_HAS_MPI
41429 
41430  // *********************************************************************
41431  // 4) Check for contiguousness
41432  // *********************************************************************
41433 #ifdef OOMPH_HAS_MPI
41434  // Only perform this checking if the mesh is not distributed
41435  // When the mesh is distributed the polylines continuity is
41436  // addressed with the sort_polylines_helper() method
41437  if (!this->is_mesh_distributed())
41438 #endif
41439  {
41440  if ( p > 0 )
41441  {
41442  //Final end point of previous line
41443  Vector<double> final_vertex_of_previous_segment;
41444  unsigned n_prev_vertex =
41445  polygon_pt->curve_section_pt(p-1)->nvertex();
41446  final_vertex_of_previous_segment =
41447  polygon_pt->polyline_pt(p-1)->
41448  vertex_coordinate(n_prev_vertex-1);
41449 
41450  unsigned prev_seg_boundary_id =
41451  polygon_pt->curve_section_pt(p-1)->boundary_id();
41452 
41453  //Find the error between the final vertex of the previous
41454  //line and the first vertex of the current line
41455  double error = 0.0;
41456  for(unsigned i=0;i<2;i++)
41457  {
41458  const double dist =
41459  final_vertex_of_previous_segment[i] -
41460  (*vector_vertex_node.begin())[i];
41461  error += dist*dist;
41462  }
41463  error = sqrt(error);
41464 
41465  //If the error is bigger than the tolerance then
41466  //we probably need to reverse, but better check
41468  {
41469  //Find the error between the final vertex of the previous
41470  //line and the last vertex of the current line
41471  double rev_error = 0.0;
41472  for(unsigned i=0;i<2;i++)
41473  {
41474  const double dist =
41475  final_vertex_of_previous_segment[i] -
41476  (*--vector_vertex_node.end())[i];
41477  rev_error += dist*dist;
41478  }
41479  rev_error = sqrt(rev_error);
41480 
41481  if(rev_error >
41483  {
41484  // It could be possible that the first segment be reversed and we
41485  // did not notice it because this check does not apply for the
41486  // first segment. We can verify if the first segment is reversed
41487  // by using the vertex number 1
41488  if (p == 1)
41489  {
41490  //Initial end point of previous line
41491  Vector<double> initial_vertex_of_previous_segment;
41492 
41493  initial_vertex_of_previous_segment =
41494  polygon_pt->polyline_pt(p-1)->
41495  vertex_coordinate(0);
41496 
41497  unsigned prev_seg_boundary_id =
41498  polygon_pt->curve_section_pt(p-1)->boundary_id();
41499 
41500  //Find the error between the initial vertex of the previous
41501  //line and the first vertex of the current line
41502  double error = 0.0;
41503  for(unsigned i=0;i<2;i++)
41504  {
41505  const double dist =
41506  initial_vertex_of_previous_segment[i] -
41507  (*vector_vertex_node.begin())[i];
41508  error += dist*dist;
41509  }
41510  error = sqrt(error); // Reversed only the previous one
41511 
41512  //If the error is bigger than the tolerance then
41513  //we probably need to reverse, but better check
41515  {
41516  //Find the error between the final vertex of the previous
41517  //line and the last vertex of the current line
41518  double rev_error = 0.0;
41519  for(unsigned i=0;i<2;i++)
41520  {
41521  const double dist =
41522  initial_vertex_of_previous_segment[i] -
41523  (*--vector_vertex_node.end())[i];
41524  rev_error += dist*dist;
41525  }
41526  rev_error = sqrt(rev_error); // Reversed both the current one and
41527  // the previous one
41528 
41529  if (rev_error >
41531  {
41532  std::ostringstream error_stream;
41533  error_stream
41534  <<"The distance between the first node of the current\n"
41535  <<"line segment (boundary " << bound << ") and either end of "
41536  << "the previous line segment\n"
41537  << "(boundary " << prev_seg_boundary_id << ") is bigger than "
41538  << "the desired tolerance " <<
41540  << "This suggests that the polylines defining the polygonal\n"
41541  << "representation are not properly ordered.\n"
41542  << "Fail on last vertex of polyline: ("
41543  << prev_seg_boundary_id<< ") and\nfirst vertex of polyline ("
41544  << bound << ").\nThis should have failed when first trying to"
41545  << " construct the\npolygon.\n";
41546  throw OomphLibError(error_stream.str(),
41547  "RefineableTriangleMesh::update_polygon_after_restart()",
41548  OOMPH_EXCEPTION_LOCATION);
41549  }
41550  else
41551  {
41552  // Reverse both
41553  // Reverse the current vector to line up with the previous one
41554  std::reverse(vector_vertex_node.begin(),
41555  vector_vertex_node.end());
41556  polygon_pt->polyline_pt(p-1)->reverse();
41557  }
41558  }
41559  else
41560  {
41561  // Reverse the previous one
41562  polygon_pt->polyline_pt(p-1)->reverse();
41563  }
41564 
41565  } // if p == 1
41566  else
41567  {
41568  std::ostringstream error_stream;
41569  error_stream
41570  <<"The distance between the first node of the current\n"
41571  <<"line segment (boundary " << bound << ") and either end of "
41572  <<"the previous line segment\n"
41573  <<"(boundary " << prev_seg_boundary_id << ") is bigger than the "
41574  <<"desired tolerance " <<
41576  <<"This suggests that the polylines defining the polygonal\n"
41577  <<"representation are not properly ordered.\n"
41578  << "Fail on last vertex of polyline: (" << prev_seg_boundary_id
41579  << ") and\nfirst vertex of polyline (" << bound << ").\n"
41580  << "This should have failed when first trying to construct the\n"
41581  << "polygon.\n";
41582  throw OomphLibError(
41583  error_stream.str(),
41584  "RefineableTriangleMesh::update_polygon_after_restart()",
41585  OOMPH_EXCEPTION_LOCATION);
41586  }
41587  }
41588  else
41589  {
41590  //Reverse the current vector to line up with the previous one
41591  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
41592  }
41593  } // error
41594  } // p > 0
41595  } // is mesh not distributed
41596 
41597  // *********************************************************************
41598  // 5) Update the polylines representation
41599  // *********************************************************************
41600  // if (applied_area_length_constraint)
41601  // If only applied when there is a change then it keeps the
41602  // previous polyline representation, it means, it does not delete
41603  // the boundaries that are not part of the domain. We must update
41604  // the boundary representation
41605  {
41606  n_vertex = vector_vertex_node.size();
41607 
41608  // Now update the polyline according to the new vertices
41609  // The new one representation
41610  TriangleMeshPolyLine *tmp_polyline_pt =
41611  new TriangleMeshPolyLine(vector_vertex_node,bound);
41612 
41613  // for (unsigned h = 0; h < vector_vertex_node.size(); h++)
41614  // {
41615  // DEBP(h);
41616  // DEBP(vector_vertex_node[h][0]);
41617  // DEBP(vector_vertex_node[h][1]);
41618  // }
41619 
41620  // Create a temporal "curve section" version of the recently created
41621  // polyline
41622  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
41623 
41624  // Tolerance below which the middle point can be deleted
41625  // (ratio of deflection to element length)
41626  double unrefinement_tolerance=
41627  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
41628 
41629  // Tolerance to add points
41630  double refinement_tolerance=
41631  polygon_pt->polyline_pt(p)->refinement_tolerance();
41632 
41633  // Establish refinement and unrefinement tolerance
41634  tmp_polyline_pt->set_unrefinement_tolerance(
41635  unrefinement_tolerance);
41636  tmp_polyline_pt->set_refinement_tolerance(
41637  refinement_tolerance);
41638 
41639  // Establish the maximum length constraint
41640  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
41641  tmp_polyline_pt->set_maximum_length(maximum_length);
41642 
41643  if (n_vertex >= 2)
41644  {
41645  // Pass the connection information from the old polyline to the
41646  // new one
41647  this->copy_connection_information(polygon_pt->polyline_pt(p),
41648  tmp_curve_section_pt);
41649  }
41650 
41651  //Now update the polyline according to the new vertices but
41652  //first check if the object is allowed to delete the representation
41653  //or if it should be done by other object
41654  bool delete_it_on_destructor = false;
41655 
41656  std::set<TriangleMeshCurveSection*>::iterator it =
41657  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
41658 
41659  if (it!=this->Free_curve_section_pt.end())
41660  {
41661  this->Free_curve_section_pt.erase(it);
41662  delete polygon_pt->curve_section_pt(p);
41663  delete_it_on_destructor = true;
41664  }
41665 
41666  // *****************************************************************
41667  // Copying the new representation
41668  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
41669 
41670  // Update the Boundary - Polyline map
41671  this->Boundary_curve_section_pt[bound] = polygon_pt->curve_section_pt(p);
41672 
41673  if (delete_it_on_destructor)
41674  {
41675  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
41676  }
41677 
41678 #ifdef OOMPH_HAS_MPI
41679  // --------- Stuff for the sub_boundaries ----- Begin section --------
41680  // Verify if need to deal with sub_boundaries
41681  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41682  {
41683  // Create temporary representations for the boundaries, only to
41684  // create the mesh when calling Triangle
41685  // Clear all previous stored data
41686  this->Boundary_subpolylines[bound].clear();
41687  // Now create storage for the sub-boundaries
41688  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
41689  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41690  {
41691  // Now update the polyline according to the sub set of
41692  // vertices, set the chunk number of the polyline
41693  TriangleMeshPolyLine *sub_tmp_polyline_pt =
41694  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
41695 
41696  // Add the sub-polyline to the container to represent the boundary
41697  // in parts
41698  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
41699 
41700  // No need to send the unrefinement/refinement and maximum
41701  // length constraints since these are only temporary
41702  // representations. These polylines can be deleted once the
41703  // new polygons that represent the distributed domain have
41704  // been created
41705 
41706  } // for (isub < nsub_boundaries)
41707 
41708  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41709  // --------- Stuff for the sub_boundaries ----- End section ---------
41710 #endif // OOMPH_HAS_MPI
41711 
41712  } // update polyline representation
41713 
41714  // Delete the allocated memory for the geometric object that
41715  // represents the curvilinear boundary
41716  delete mesh_geom_obj_pt;
41717 
41718  } // npolyline
41719 
41720  // Cleanup the face mesh
41721  for(unsigned p=0;p<n_polyline;p++)
41722  {
41723  face_mesh_pt[p]->flush_node_storage();
41724  delete face_mesh_pt[p];
41725  }
41726 
41727 }
41728 
41729 
41730 //======================================================================
41731 /// \short Updates the open curve representation after restart
41732 //======================================================================
41733 template <class ELEMENT>
41736 {
41737  // **********************************************************************
41738  // 1) Get the vertices along the boundaries ids of the polylines and
41739  // update them
41740  // **********************************************************************
41741 
41742  // (1.1) Get the face mesh representation
41743  Vector<Mesh*> face_mesh_pt;
41744  get_face_mesh_representation(open_curve_pt,face_mesh_pt);
41745 
41746  // (1.2) Create vertices of the polylines by using the vertices of the
41747  // FaceElements
41748  Vector<double> vertex_coord(3); // zeta,x,y
41749  Vector<double> bound_left(1);
41750  Vector<double> bound_right(1);
41751 
41752  const unsigned ncurve_section = open_curve_pt->ncurve_section();
41753  // Go for each curve section
41754  for(unsigned cs = 0; cs < ncurve_section; cs++)
41755  {
41756  // Get the MeshAsGeomObject representation just once per polyline,
41757  // this object is only used by the
41758  // refine_boundary_constrained_by_target_area() method. We get it here
41759  // to ensure that all processors (in a distributed context) get this
41760  // representation just once, and because an AllToAll MPI communication
41761  // is used in this calling
41762  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt[cs]);
41763 
41764  //Get the boundary id
41765  const unsigned bound = open_curve_pt->curve_section_pt(cs)->boundary_id();
41766 
41767  /// Use a vector of vector for vertices and target areas to deal
41768  /// with the cases when the boundaries are split bn the
41769  /// distribution process. Internal boundaries may be completely or
41770  /// partially overlapped by shared boundaries
41771 
41772  // Loop over the face elements and add their vertices (they are
41773  // automatically sorted because of the set)
41774  const unsigned nface_element = face_mesh_pt[cs]->nelement();
41775  // Store the non halo elements and the element at the other side of
41776  // the boundary (whatever it be halo or not), the first will be the
41777  // ones from which we will get the vertices (in even position)
41778  Vector<FiniteElement*> non_halo_doubled_face_element_pt;
41779 
41780  // Map to store the index of the face element on a boundary
41781  std::map<FiniteElement*,unsigned> face_element_index_on_boundary;
41782 
41783  // Map to know the already sorted face elements
41784  std::map<FiniteElement*,bool> face_element_done;
41785 
41786  for(unsigned ef = 0; ef < nface_element; ++ef)
41787  {
41788  FiniteElement* ele_face_pt = face_mesh_pt[cs]->finite_element_pt(ef);
41789 
41790  // Skip the halo elements (not used as base elements, only
41791  // include those elements which one of its counterparts -- at the
41792  // other side of the boundary -- is non halo)
41793 #ifdef OOMPH_HAS_MPI
41794  if (this->is_mesh_distributed())
41795  {
41796  // Only work with non-halo elements
41797  if (ele_face_pt->is_halo()) {continue;}
41798  }
41799 #endif
41800 
41801  // Check if not already done
41802  if (!face_element_done[ele_face_pt])
41803  {
41804  // Add the element and look for the element at the other side
41805  // of the boundary to add it immediately after the new added
41806  // element
41807  non_halo_doubled_face_element_pt.push_back(ele_face_pt);
41808  // Create the map of the face element with the index
41809  face_element_index_on_boundary[ele_face_pt] = ef;
41810  // Mark the current element as done
41811  face_element_done[ele_face_pt] = true;
41812  // Get the number of nodes
41813  const unsigned nnodes = ele_face_pt->nnode();
41814  // Get the left and right node to look for the elements at the
41815  // other side of the boundary
41816  Node* left_node_pt = ele_face_pt->node_pt(0);
41817  Node* right_node_pt = ele_face_pt->node_pt(nnodes-1);
41818 
41819 #ifdef PARANOID
41820  // Flag to know if the element at the other side of the
41821  // boundary was found
41822  bool found_other_side_face_ele = false;
41823 #endif
41824  for (unsigned iface = 0; iface < nface_element; iface++)
41825  {
41826  // Get the candidate face element
41827  FiniteElement *cele_face_pt =
41828  face_mesh_pt[cs]->finite_element_pt(iface);
41829  // Check if not already done
41830  if (!face_element_done[cele_face_pt])
41831  {
41832  Node* cleft_node_pt = cele_face_pt->node_pt(0);
41833  Node* cright_node_pt = cele_face_pt->node_pt(nnodes-1);
41834 
41835  // Check if the nodes are the same
41836  if ((left_node_pt == cleft_node_pt &&
41837  right_node_pt == cright_node_pt) ||
41838  (left_node_pt == cright_node_pt &&
41839  right_node_pt == cleft_node_pt))
41840  {
41841  // Add the element to the storage
41842  non_halo_doubled_face_element_pt.push_back(cele_face_pt);
41843  // ... and mark the element as done
41844  face_element_done[cele_face_pt] = true;
41845  // Create the map of the face element with the index
41846  face_element_index_on_boundary[cele_face_pt] = iface;
41847 #ifdef PARANOID
41848  // Set the flag of found other side face element
41849  found_other_side_face_ele = true;
41850 #endif
41851  break;
41852  }
41853  }
41854  } // (iface < nface_element)
41855 
41856 #ifdef PARANOID
41857  if (!found_other_side_face_ele)
41858  {
41859  std::ostringstream error_message;
41860  error_message
41861  << "The face element at the other side of the boundary ("
41862  << bound << ") was not found!!\n"
41863  << "These are the nodes of the face element:\n"
41864  << "("<<left_node_pt->x(0)<<", "<<left_node_pt->x(1)<<") "
41865  << "and ("<<right_node_pt->x(0)<<","<<right_node_pt->x(1)<<")\n\n";
41866  throw OomphLibError(error_message.str(),
41867  "RefineableTriangleMesh::update_open_curve_after_restart()",
41868  OOMPH_EXCEPTION_LOCATION);
41869  }
41870 #endif
41871  } // if (!face_ele_done[ele_face_pt])
41872 
41873  } // (ef < nface_element)
41874 
41875  // Clear the map of the already done face elements
41876  // This will now be used to sort the face elements
41877  face_element_done.clear();
41878 
41879  // Set of coordinates that are on the boundary
41880  // The entries are sorted on first entry in vector which stores
41881  // the boundary coordinate so the vertices come out in order!
41882  std::set<Vector<double> > vertex_nodes;
41883 
41884  // Vector to store the vertices, transfer the sorted vertices from the
41885  // set to this vector, --- including the z-value ---
41886  Vector<Vector<double> > tmp_vector_vertex_node;
41887 
41888  // Vector to store the coordinates of the polylines, same as the
41889  // tmp_vector_vertex_node vector (after adding more nodes) but
41890  // --- without the z-value ---, used to re-generate the polylines
41891  Vector<Vector<double> > vector_vertex_node;
41892 
41893 #ifdef OOMPH_HAS_MPI
41894  // Indicates if the set of vertices give rise to a internal
41895  // boundary that will be used as shared boundary or as normal
41896  // internal boundary -- Only used to deal with internal boundaries
41897  // in a distributed scheme
41898  std::vector<bool> internal_to_shared_boundary;
41899 
41900  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
41901  // Set of coordinates that are on the boundary (splitted boundary version)
41902  // The first vector is used to allocate the points for each sub-boundary
41903  // Set entries are ordered on first entry in vector which stores
41904  // the boundary coordinate so the vertices come out in order!
41905  Vector<std::set<Vector<double> > > sub_vertex_nodes;
41906 
41907  // Vector to store the vertices, transfer the sorted vertices from the
41908  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
41909  Vector<Vector<Vector<double> > > sub_tmp_vector_vertex_node;
41910 
41911  // Vector to store the coordinates of the polylines that will represent
41912  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
41913  // but --- without the z-value ---, used to generate the sub-polylines
41914  Vector<Vector<Vector<double> > > sub_vector_vertex_node;
41915 
41916  // --------- Stuff to deal with splitted boundaries ----------- End ------
41917 #endif
41918 
41919  // Sort face elements, separate those with both nonhalo face
41920  // elements from those with one halo and one nonhalo face element
41921 
41922  // Number of done face elements
41923  unsigned nsorted_face_elements = 0;
41924 
41925 #ifdef OOMPH_HAS_MPI
41926  // Counter for sub_boundaries
41927  unsigned nsub_boundaries = 0;
41928 #endif // #ifdef OOMPH_HAS_MPI
41929 
41930  // Total number of non halo double face element
41931  const unsigned nnon_halo_doubled_face_ele =
41932  non_halo_doubled_face_element_pt.size();
41933 
41934  // Continue until all the face elements have been sorted
41935  // This while is to deal with the cases of splitted boundaries
41936  while(nsorted_face_elements < nnon_halo_doubled_face_ele)
41937  {
41938  // Get and initial face element
41939  FiniteElement* ele_face_pt = 0;
41940  FiniteElement* repeated_ele_face_pt = 0;
41941 #ifdef PARANOID
41942  bool found_initial_face_element = false;
41943 #endif
41944 
41945  // Flag to know if we are working with a face element which the
41946  // face element at the other side of the boundary is also non
41947  // halo
41948  bool both_root_face_elements_are_nonhalo = false;
41949 
41950  unsigned iface = 0;
41951  for (iface = 0; iface < nnon_halo_doubled_face_ele; iface+=2)
41952  {
41953  ele_face_pt = non_halo_doubled_face_element_pt[iface];
41954  // If not done then take it as initial face element
41955  if (!face_element_done[ele_face_pt])
41956  {
41957  // Mark it as done
41958  face_element_done[ele_face_pt] = true;
41959  // Get the other side boundary face element
41960  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iface+1];
41961  // ... also mark as done the repeated face element
41962  face_element_done[repeated_ele_face_pt] = true;
41963 
41964 #ifdef OOMPH_HAS_MPI
41965  if (!repeated_ele_face_pt->is_halo())
41966  {both_root_face_elements_are_nonhalo = true;}
41967 #endif // #ifdef OOMPH_HAS_MPI
41968 
41969  // Plus two because internal boundaries have
41970  // two face elements per each edge
41971  nsorted_face_elements+=2;
41972  iface+=2;
41973 #ifdef PARANOID
41974  // And set the flag to true
41975  found_initial_face_element = true;
41976 #endif
41977  break;
41978  }
41979  }
41980 
41981 #ifdef PARANOID
41982  if (!found_initial_face_element)
41983  {
41984  std::ostringstream error_message;
41985  error_message
41986  <<"Could not find an initial face element for the current segment\n";
41987  // << "----- Possible memory leak -----\n";
41988  throw OomphLibError(error_message.str(),
41989  OOMPH_CURRENT_FUNCTION,
41990  OOMPH_EXCEPTION_LOCATION);
41991  }
41992 #endif
41993 
41994  // Local set of coordinates that are on the boundary Set entries
41995  // are ordered on first entry in vector which stores the boundary
41996  // coordinate so the vertices come out in order
41997  std::set<Vector<double> > local_vertex_nodes;
41998 
41999  // Vector to store the vertices, transfer the sorted vertices from the
42000  // set (local) to this vector (local), --- including the z-value ---
42001  Vector<Vector<double> > local_tmp_vector_vertex_node;
42002 
42003  // ------------------------------------------------------------------
42004  // ------------------------------------------------------------------
42005  // Add the vertices of the initial face element to the set of local
42006  // sorted vertices
42007  // ------------------------------------------------------------------
42008  // ------------------------------------------------------------------
42009  const unsigned nnode = ele_face_pt->nnode();
42010  // Add the left-hand node to the set:
42011  // Boundary coordinate
42012  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
42013  vertex_coord[0] = bound_left[0];
42014 
42015  // Actual coordinates
42016  for(unsigned i=0;i<2;i++)
42017  {
42018  vertex_coord[i+1] = ele_face_pt->node_pt(0)->x(i);
42019  }
42020  local_vertex_nodes.insert(vertex_coord);
42021 
42022  // Add the right-hand node to the set:
42023  // Boundary coordinate
42024  ele_face_pt->node_pt(nnode-1)->get_coordinates_on_boundary(bound,
42025  bound_right);
42026  vertex_coord[0] = bound_right[0];
42027 
42028  // Actual coordinates
42029  for(unsigned i=0;i<2;i++)
42030  {
42031  vertex_coord[i+1] = ele_face_pt->node_pt(nnode-1)->x(i);
42032  }
42033  local_vertex_nodes.insert(vertex_coord);
42034 
42035  // The initial and final node on the set
42036  Node *first_node_pt = ele_face_pt->node_pt(0);
42037  Node *last_node_pt = ele_face_pt->node_pt(nnode-1);
42038 
42039  // Continue iterating if a new face element has been added to the
42040  // list
42041  bool face_element_added = false;
42042 
42043  // While a new face element has been added to the set of sorted
42044  // face elements then re-iterate
42045  do
42046  {
42047  // Start from the next face elements since we have already
42048  // added the previous one as the initial face element (any
42049  // previous face element had to be added on previous
42050  // iterations)
42051  for (unsigned iiface=iface;
42052  iiface<nnon_halo_doubled_face_ele;iiface+=2)
42053  {
42054  face_element_added = false;
42055  ele_face_pt = non_halo_doubled_face_element_pt[iiface];
42056 
42057  // Check that the face element with which we are working has
42058  // the same conditions as the root face element (both faces
42059  // are nonhalo or one face is halo and the other nonhalo)
42060 
42061  // Get the face element at the other side of the boundary
42062  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface+1];
42063  bool both_face_elements_are_nonhalo = false;
42064 
42065 #ifdef OOMPH_HAS_MPI
42066  if (!repeated_ele_face_pt->is_halo())
42067  {both_face_elements_are_nonhalo = true;}
42068 #endif // #ifdef OOMPH_HAS_MPI
42069 
42070  if (!face_element_done[ele_face_pt] &&
42071  (both_face_elements_are_nonhalo ==
42072  both_root_face_elements_are_nonhalo))
42073  {
42074  // Get each individual node to check if they are contiguous
42075  const unsigned nlnode = ele_face_pt->nnode();
42076  Node* left_node_pt = ele_face_pt->node_pt(0);
42077  Node* right_node_pt = ele_face_pt->node_pt(nlnode-1);
42078 
42079  if (left_node_pt == first_node_pt)
42080  {
42081  first_node_pt = right_node_pt;
42082  face_element_added = true;
42083  }
42084  else if (left_node_pt == last_node_pt)
42085  {
42086  last_node_pt = right_node_pt;
42087  face_element_added = true;
42088  }
42089  else if (right_node_pt == first_node_pt)
42090  {
42091  first_node_pt = left_node_pt;
42092  face_element_added = true;
42093  }
42094  else if (right_node_pt == last_node_pt)
42095  {
42096  last_node_pt = left_node_pt;
42097  face_element_added = true;
42098  }
42099 
42100  if (face_element_added)
42101  {
42102  // Add the left-hand node to the set:
42103  // Boundary coordinate
42104  left_node_pt->get_coordinates_on_boundary(bound,bound_left);
42105  vertex_coord[0] = bound_left[0];
42106 
42107  // Actual coordinates
42108  for(unsigned i=0;i<2;i++)
42109  {
42110  vertex_coord[i+1] = left_node_pt->x(i);
42111  }
42112  local_vertex_nodes.insert(vertex_coord);
42113 
42114  // Add the right-hand nodes to the set:
42115  // Boundary coordinate
42116  right_node_pt->get_coordinates_on_boundary(bound,bound_right);
42117  vertex_coord[0] = bound_right[0];
42118 
42119  // Actual coordinates
42120  for(unsigned i=0;i<2;i++)
42121  {
42122  vertex_coord[i+1] = right_node_pt->x(i);
42123  }
42124  local_vertex_nodes.insert(vertex_coord);
42125 
42126  // Mark as done only if one of its nodes has been
42127  // added to the list
42128  face_element_done[ele_face_pt] = true;
42129  // .. also mark as done the face element at the othe side of
42130  // the boundary
42131  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface+1];
42132  face_element_done[repeated_ele_face_pt] = true;
42133  // ... and increase the number of sorted face elements
42134  nsorted_face_elements+=2;
42135 
42136  break;
42137  }
42138 
42139  } // if (!face_element_done[[ele_face_pt])
42140  } // for (iiface<nnon_halo_doubled_face_ele)
42141  }while(face_element_added &&
42142  (nsorted_face_elements < nnon_halo_doubled_face_ele));
42143 
42144  // -------------------------------------------------------------
42145  // At this point we already have a sorted set of nodes and can
42146  // be used to peform the unrefinement and refinement procedures
42147  // -------------------------------------------------------------
42148 
42149  // Get the number of nodes on the list
42150  const unsigned nlocal_nodes = local_vertex_nodes.size();
42151  // Change representation to vector for easy of handling ...
42152  local_tmp_vector_vertex_node.resize(nlocal_nodes);
42153 
42154  // Copy the vertices of the nodes
42155  unsigned counter = 0;
42156  std::set<Vector<double> >::iterator it_vertex;
42157  for (it_vertex = local_vertex_nodes.begin();
42158  it_vertex != local_vertex_nodes.end();
42159  it_vertex++)
42160  {
42161  local_tmp_vector_vertex_node[counter].resize(3);
42162  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
42163  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
42164  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
42165  counter++;
42166  }
42167 
42168  // The unrefinement and refinement process needs to be applied
42169  // from the bottom-left node since the internal open curve could
42170  // lie on the shared boundaries
42171  if (local_tmp_vector_vertex_node[nlocal_nodes-1][2] <
42172  local_tmp_vector_vertex_node[0][2])
42173  {
42174  std::reverse(local_tmp_vector_vertex_node.begin(),
42175  local_tmp_vector_vertex_node.end());
42176  }
42177  else if (local_tmp_vector_vertex_node[nlocal_nodes-1][2] ==
42178  local_tmp_vector_vertex_node[0][2])
42179  {
42180  if (local_tmp_vector_vertex_node[nlocal_nodes-1][1] <
42181  local_tmp_vector_vertex_node[0][1])
42182  {
42183  std::reverse(local_tmp_vector_vertex_node.begin(),
42184  local_tmp_vector_vertex_node.end());
42185  }
42186  }
42187 
42188  // ****************************************************************
42189  // 3) Create the vertices along the boundary using the target
42190  // area to define the distance among them
42191  // ****************************************************************
42192 
42193  // Clear the local containter to recover the nodes ordered using
42194  // the zeta value
42195  local_vertex_nodes.clear();
42196 
42197  // At the end of each unrefinement/refinement step store the new
42198  // nodes on the set that will give rise to the vertices of the
42199  // new polyline representation
42200  const unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
42201  for (unsigned i = 0; i < nnew_nodes; i++)
42202  {
42203  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
42204  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
42205  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
42206  vertex_nodes.insert(vertex_coord); // Global container
42207  local_vertex_nodes.insert(vertex_coord);
42208  }
42209 
42210 #ifdef OOMPH_HAS_MPI
42211  if (this->is_mesh_distributed())
42212  {
42213  // Add the set of vertices for the boundary, this will help to
42214  // detect if we need to deal with sub_boundaries and
42215  // sub_polylines representations
42216  sub_vertex_nodes.push_back(local_vertex_nodes);
42217  // Increase the counter for sub_boundaries
42218  nsub_boundaries++;
42219 
42220  // Mark if the polyline created by these vertices will be used
42221  // as a shared boundary or as an internal boundary
42222  if (both_root_face_elements_are_nonhalo)
42223  {internal_to_shared_boundary.push_back(false);}
42224  else
42225  {internal_to_shared_boundary.push_back(true);}
42226  }
42227 #endif
42228 
42229  } // while(nsorted_face_elements < nnon_halo_doubled_face_ele)
42230  // This while is in charge of sorting all the face elements to
42231  // create the new representation of the polyline (also deals
42232  // with the sub-boundary cases)
42233 
42234  // Now turn into vector for ease of handling...
42235  const unsigned npoly_vertex = vertex_nodes.size();
42236  tmp_vector_vertex_node.resize(npoly_vertex);
42237  unsigned count = 0;
42238  std::set<Vector<double> >::iterator it;
42239  for (it = vertex_nodes.begin(); it!=vertex_nodes.end(); ++it)
42240  {
42241  tmp_vector_vertex_node[count].resize(3);
42242  tmp_vector_vertex_node[count][0] = (*it)[0];
42243  tmp_vector_vertex_node[count][1] = (*it)[1];
42244  tmp_vector_vertex_node[count][2] = (*it)[2];
42245  ++count;
42246  }
42247 
42248 #ifdef OOMPH_HAS_MPI
42249  // Check that the number of set of vertices marked to be shared or
42250  // internal boundaries be the same as the total number of
42251  // sub-boundaries
42252 #ifdef PARANOID
42253  const unsigned nsub_boundaries_set = sub_vertex_nodes.size();
42254  const unsigned ninternal_to_shared_boundaries =
42255  internal_to_shared_boundary.size();
42256  if (nsub_boundaries_set != ninternal_to_shared_boundaries)
42257  {
42258  std::ostringstream error_message;
42259  error_message
42260  << "The number of found sub-boundaries and the number of marked "
42261  << "internal\nboundaries are different\n"
42262  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
42263  << "Number of marked internal boundaries: ("
42264  << ninternal_to_shared_boundaries << ")\n\n";
42265  throw OomphLibError(error_message.str(),
42266  "RefineableTriangleMesh::update_open_curve_after_restart()",
42267  OOMPH_EXCEPTION_LOCATION);
42268  }
42269 #endif
42270 
42271  // --------- Stuff for the sub_boundaries ----- Begin section -------
42272 #ifdef PARANOID
42273  if (nsub_boundaries_set != nsub_boundaries)
42274  {
42275  std::ostringstream error_message;
42276  error_message
42277  << "The number of found sub-boundaries and the number of counted\n"
42278  << "sub-boundaries are different:\n"
42279  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
42280  << "Number of counted sub-boundaries: ("<<nsub_boundaries<<")\n\n";
42281  throw OomphLibError(error_message.str(),
42282  "RefineableTriangleMesh::update_open_curve_after_restart()",
42283  OOMPH_EXCEPTION_LOCATION);
42284  }
42285 #endif
42286 
42287  // Verify if need to deal with sub_boundaries
42288  if (this->is_mesh_distributed() && nsub_boundaries > 1)
42289  {
42290  // Mark the boundary as been splitted in the partition process
42291  this->Boundary_was_splitted[bound] = true;
42292  // Resize the vector to store the info. of sub-boundaries
42293  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
42294  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42295  {
42296  // Turn info. into vector for ease of handling...
42297  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
42298  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
42299  unsigned subcount = 0;
42300  std::set<Vector<double> >::iterator subit;
42301  for(subit = sub_vertex_nodes[isub].begin();
42302  subit != sub_vertex_nodes[isub].end(); ++subit)
42303  {
42304  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
42305  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
42306  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
42307  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
42308  ++subcount;
42309  }
42310  }
42311  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42312  // --------- Stuff for the sub_boundaries ----- End section ----------
42313 #endif // OOMPH_HAS_MPI
42314 
42315  // For further processing the three-dimensional vector has to be
42316  // reduced to a two-dimensional vector
42317  unsigned n_vertex=tmp_vector_vertex_node.size();
42318 
42319  // Resize the vector for vectices
42320  vector_vertex_node.resize(n_vertex);
42321  for(unsigned i=0;i<n_vertex;i++)
42322  {
42323  vector_vertex_node[i].resize(2);
42324  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
42325  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
42326  }
42327 
42328 #ifdef OOMPH_HAS_MPI
42329  // --------- Stuff for the sub_boundaries ----- Begin section ----------
42330  // Verify if need to deal with sub_boundaries
42331  if (this->is_mesh_distributed() && nsub_boundaries > 1)
42332  {
42333  // For further processing the three-dimensional vector
42334  // has to be reduced to a two-dimensional vector
42335  // Resize the vector to store the info. of sub-boundaries
42336  sub_vector_vertex_node.resize(nsub_boundaries);
42337  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42338  {
42339  const unsigned subn_vertex =
42340  sub_tmp_vector_vertex_node[isub].size();
42341  // Resize the vector for vectices
42342  sub_vector_vertex_node[isub].resize(subn_vertex);
42343  for(unsigned i=0;i<subn_vertex;i++)
42344  {
42345  sub_vector_vertex_node[isub][i].resize(2);
42346  sub_vector_vertex_node[isub][i][0]=
42347  sub_tmp_vector_vertex_node[isub][i][1];
42348  sub_vector_vertex_node[isub][i][1]=
42349  sub_tmp_vector_vertex_node[isub][i][2];
42350  }
42351  }
42352  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42353 
42354  // We already have the info. for the sub-boundaries (if necessary) and
42355  // then we can create the sub-boundaries representations to ease the
42356  // generation of the mesh by Triangle
42357 
42358  // --------- Stuff for the sub_boundaries ----- End section ------------
42359 #endif // OOMPH_HAS_MPI
42360 
42361  // *********************************************************************
42362  // 4) Check for contiguousness
42363  // *********************************************************************
42364 #ifdef OOMPH_HAS_MPI
42365  // Only perform this checking if the mesh is not distributed
42366  // When the mesh is distributed the polylines continuity is
42367  // addressed with the sort_polylines_helper() method
42368  if (!this->is_mesh_distributed())
42369 #endif
42370  {
42371  if ( cs > 0 )
42372  {
42373  //Final end point of previous line
42374  Vector<double> final_vertex_of_previous_segment;
42375  unsigned n_prev_vertex =
42376  open_curve_pt->curve_section_pt(cs-1)->nvertex();
42377  final_vertex_of_previous_segment =
42378  open_curve_pt->polyline_pt(cs-1)->
42379  vertex_coordinate(n_prev_vertex-1);
42380 
42381  unsigned prev_seg_boundary_id =
42382  open_curve_pt->curve_section_pt(cs-1)->boundary_id();
42383 
42384  //Find the error between the final vertex of the previous
42385  //line and the first vertex of the current line
42386  double error = 0.0;
42387  for(unsigned i=0;i<2;i++)
42388  {
42389  const double dist =
42390  final_vertex_of_previous_segment[i] -
42391  (*vector_vertex_node.begin())[i];
42392  error += dist*dist;
42393  }
42394  error = sqrt(error);
42395 
42396  //If the error is bigger than the tolerance then
42397  //we probably need to reverse, but better check
42399  {
42400  //Find the error between the final vertex of the previous
42401  //line and the last vertex of the current line
42402  double rev_error = 0.0;
42403  for(unsigned i=0;i<2;i++)
42404  {
42405  const double dist =
42406  final_vertex_of_previous_segment[i] -
42407  (*--vector_vertex_node.end())[i];
42408  rev_error += dist*dist;
42409  }
42410  rev_error = sqrt(rev_error);
42411 
42412  if(rev_error >
42414  {
42415  // It could be possible that the first segment be reversed and we
42416  // did not notice it because this check does not apply for the
42417  // first segment. We can verify if the first segment is reversed
42418  // by using the vertex number 1
42419  if (cs == 1)
42420  {
42421  //Initial end point of previous line
42422  Vector<double> initial_vertex_of_previous_segment;
42423 
42424  initial_vertex_of_previous_segment =
42425  open_curve_pt->polyline_pt(cs-1)->vertex_coordinate(0);
42426 
42427  unsigned prev_seg_boundary_id =
42428  open_curve_pt->curve_section_pt(cs-1)->boundary_id();
42429 
42430  //Find the error between the initial vertex of the previous
42431  //line and the first vertex of the current line
42432  double error = 0.0;
42433  for(unsigned i=0;i<2;i++)
42434  {
42435  const double dist =
42436  initial_vertex_of_previous_segment[i] -
42437  (*vector_vertex_node.begin())[i];
42438  error += dist*dist;
42439  }
42440  error = sqrt(error); // Reversed only the previous one
42441 
42442  //If the error is bigger than the tolerance then
42443  //we probably need to reverse, but better check
42445  {
42446  //Find the error between the final vertex of the previous
42447  //line and the last vertex of the current line
42448  double rev_error = 0.0;
42449  for(unsigned i=0;i<2;i++)
42450  {
42451  const double dist =
42452  initial_vertex_of_previous_segment[i] -
42453  (*--vector_vertex_node.end())[i];
42454  rev_error += dist*dist;
42455  }
42456  rev_error = sqrt(rev_error); // Reversed both the current
42457  // one and the previous one
42458 
42459  if (rev_error >
42461  {
42462  std::ostringstream error_stream;
42463  error_stream
42464  <<"The distance between the first node of the current\n"
42465  <<"line segment (boundary "<<bound<<") and either end of "
42466  <<"the previous line segment\n"
42467  <<"(boundary "<<prev_seg_boundary_id<<") is bigger than"
42468  << " the desired tolerance " <<
42470  <<"This suggests that the polylines defining the polygonal\n"
42471  <<"representation are not properly ordered.\n"
42472  <<"Fail on last vertex of polyline: ("
42473  <<prev_seg_boundary_id<<") and\nfirst vertex of polyline ("
42474  <<bound<< ").\nThis should have failed when first trying to "
42475  <<"construct the\npolygon.\n";
42476  throw OomphLibError(error_stream.str(),
42477  "RefineableTriangleMesh::update_open_curve_after_restart()",
42478  OOMPH_EXCEPTION_LOCATION);
42479  }
42480  else
42481  {
42482  // Reverse both
42483  // Reverse the current vector to line up with the previous one
42484  std::reverse(vector_vertex_node.begin(),
42485  vector_vertex_node.end());
42486  open_curve_pt->polyline_pt(cs-1)->reverse();
42487  }
42488  }
42489  else
42490  {
42491  // Reverse the previous one
42492  open_curve_pt->polyline_pt(cs-1)->reverse();
42493  }
42494 
42495  } // if (cs == 1)
42496  else
42497  {
42498  std::ostringstream error_stream;
42499  error_stream
42500  <<"The distance between the first node of the current\n"
42501  <<"line segment (boundary " << bound << ") and either end of "
42502  <<"the previous line segment\n"
42503  <<"(boundary " << prev_seg_boundary_id << ") is bigger than the "
42504  <<"desired tolerance " <<
42506  <<"This suggests that the polylines defining the polygonal\n"
42507  <<"representation are not properly ordered.\n"
42508  <<"Fail on last vertex of polyline: (" << prev_seg_boundary_id
42509  <<") and\nfirst vertex of polyline (" << bound << ").\n"
42510  <<"This should have failed when first trying to construct the\n"
42511  <<"polygon.\n";
42512  throw OomphLibError(
42513  error_stream.str(),
42514  "RefineableTriangleMesh::update_open_curve_after_restart()",
42515  OOMPH_EXCEPTION_LOCATION);
42516  }
42517  }
42518  else
42519  {
42520  //Reverse the current vector to line up with the previous one
42521  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
42522  }
42523  } // error
42524  } // (cs > 0)
42525  } // is mesh not distributed
42526 
42527  // DEBP(applied_area_length_constraint);
42528  // DEBP(p);
42529  // getchar();
42530  // *********************************************************************
42531  // 5) Update the polylines representation
42532  // *********************************************************************
42533  // if (applied_area_length_constraint)
42534  // If only applied when there is a change then it keeps the
42535  // previous polyline representation, it means, it does not delete
42536  // the boundaries that are not part of the domain. We must update
42537  // the boundary representation
42538  {
42539  n_vertex = vector_vertex_node.size();
42540 
42541  // Now update the polyline according to the new vertices
42542  // The new one representation
42543  TriangleMeshPolyLine *tmp_polyline_pt =
42544  new TriangleMeshPolyLine(vector_vertex_node,bound);
42545 
42546  // Create a temporal "curve section" version of the recently created
42547  // polyline
42548  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
42549 
42550  // Tolerance below which the middle point can be deleted
42551  // (ratio of deflection to element length)
42552  double unrefinement_tolerance=
42553  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
42554 
42555  // Tolerance to add points
42556  double refinement_tolerance=
42557  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
42558 
42559  // Establish refinement and unrefinement tolerance
42560  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
42561  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
42562 
42563  // Establish the maximum length constraint
42564  double maximum_length = open_curve_pt->polyline_pt(cs)->maximum_length();
42565  tmp_polyline_pt->set_maximum_length(maximum_length);
42566 
42567  if (n_vertex >= 2)
42568  {
42569  // Pass the connection information from the old polyline to the
42570  // new one
42571  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
42572  tmp_curve_section_pt);
42573  }
42574 
42575  //Now update the polyline according to the new vertices but first
42576  //check if the object is allowed to delete the representation or
42577  //if it should be done by other object
42578  bool delete_it_on_destructor = false;
42579 
42580  std::set<TriangleMeshCurveSection*>::iterator it =
42581  this->Free_curve_section_pt.find(open_curve_pt->curve_section_pt(cs));
42582 
42583  if (it!=this->Free_curve_section_pt.end())
42584  {
42585  this->Free_curve_section_pt.erase(it);
42586  delete open_curve_pt->curve_section_pt(cs);
42587  delete_it_on_destructor = true;
42588  }
42589 
42590  // *****************************************************************
42591  // Copying the new representation
42592  open_curve_pt->curve_section_pt(cs) = tmp_polyline_pt;
42593 
42594  // Update the Boundary - Polyline map
42595  this->Boundary_curve_section_pt[bound]=open_curve_pt->curve_section_pt(cs);
42596 
42597  if (delete_it_on_destructor)
42598  {
42599  this->Free_curve_section_pt.insert(open_curve_pt->curve_section_pt(cs));
42600  }
42601 
42602 #ifdef OOMPH_HAS_MPI
42603 
42604  // If there are not sub-boundaries mark the boundary if need to be
42605  // trated as shared or as internal boundary
42606  if (this->is_mesh_distributed() && nsub_boundaries == 1)
42607  {
42608  // Clear all previous stored data
42609  this->Boundary_marked_as_shared_boundary[bound].clear();
42610 
42611  // .. and store the flag for the boundary
42612  this->Boundary_marked_as_shared_boundary[bound].push_back(
42613  internal_to_shared_boundary[0]);
42614  }
42615  // --------- Stuff for the sub_boundaries ----- Begin section --------
42616  // Verify if need to deal with sub_boundaries
42617  else if (this->is_mesh_distributed() && nsub_boundaries > 1)
42618  {
42619  // Create temporary representations for the boundaries, only to
42620  // create the mesh when calling Triangle
42621  // Clear all previous stored data
42622  this->Boundary_subpolylines[bound].clear();
42623  // Now create storage for the sub-boundaries
42624  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
42625 
42626  // Clear all previous stored data
42627  this->Boundary_marked_as_shared_boundary[bound].clear();
42628  // Create storage to mark the internal boundaries as shared
42629  // boundaries
42630  this->Boundary_marked_as_shared_boundary[bound].resize(nsub_boundaries);
42631  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42632  {
42633  // Now update the polyline according to the sub set of
42634  // vertices, set the chunk number of the polyline
42635  TriangleMeshPolyLine *sub_tmp_polyline_pt =
42636  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
42637 
42638  // Add the sub-polyline to the container to represent the
42639  // boundary in parts
42640  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
42641 
42642  // Copy the flag that mark the boundary as internal or as
42643  // shared bound
42644  this->Boundary_marked_as_shared_boundary[bound][isub] =
42645  internal_to_shared_boundary[isub];
42646 
42647  // No need to send the unrefinement/refinement and maximum
42648  // length constraints since these are only temporary
42649  // representations
42650 
42651  }
42652 
42653  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42654  // --------- Stuff for the sub_boundaries ----- End section ---------
42655 #endif // OOMPH_HAS_MPI
42656 
42657  } // update polyline representation
42658 
42659  // Delete the allocated memory for the geometric object
42660  // that represents the curvilinear boundary
42661  delete mesh_geom_obj_pt;
42662 
42663  } // npolyline
42664 
42665  // Cleanup the face mesh
42666  for(unsigned p = 0; p < ncurve_section; p++)
42667  {
42668  face_mesh_pt[p]->flush_node_storage();
42669  delete face_mesh_pt[p];
42670  }
42671 
42672 }
42673 
42674 #ifdef OOMPH_HAS_MPI
42675 //======================================================================
42676 /// \short Updates the shared polylines representation after restart
42677 //======================================================================
42678 template <class ELEMENT>
42681  &vector_polyline_pt)
42682 {
42683  // Go through all the shared boundaries/polylines
42684  const unsigned npolylines = vector_polyline_pt.size();
42685  for (unsigned pp = 0; pp < npolylines; pp++)
42686  {
42687  // Get the boundary of the current polyline
42688  const unsigned b = vector_polyline_pt[pp]->boundary_id();
42689 
42690  // Get the edges of the shared boundary elements that create the
42691  // shared boundary and store the shared boundary elements from where
42692  // were created
42693  std::map<std::pair<Node*, Node*>, FiniteElement*> halo_edge_element_pt;
42694  std::map<std::pair<Node*, Node*>, FiniteElement*> nonhalo_edge_element_pt;
42695 
42696  // Store the nodes that define the edges
42697  Vector<Node*> halo_edge_nodes_pt;
42698  Vector<Node*> nonhalo_edge_nodes_pt;
42699 
42700  // Go through the shared boundary elements and store their edges
42701  const unsigned nshared_bound_ele = this->nshared_boundary_element(b);
42702  for (unsigned e = 0; e < nshared_bound_ele; e++)
42703  {
42704  // Get the shared boundary element
42705  FiniteElement* current_ele_pt = this->shared_boundary_element_pt(b, e);
42706 
42707  // Get the corner nodes, the first three nodes
42708  Node *first_node_pt = current_ele_pt->node_pt(0);
42709  Node *second_node_pt = current_ele_pt->node_pt(1);
42710  Node *third_node_pt = current_ele_pt->node_pt(2);
42711 
42712  // Check if the elements is halo
42713  if (!current_ele_pt->is_halo())
42714  {
42715  // Store the edges
42716  nonhalo_edge_nodes_pt.push_back(first_node_pt);
42717  nonhalo_edge_nodes_pt.push_back(second_node_pt);
42718 
42719  nonhalo_edge_nodes_pt.push_back(second_node_pt);
42720  nonhalo_edge_nodes_pt.push_back(third_node_pt);
42721 
42722  nonhalo_edge_nodes_pt.push_back(third_node_pt);
42723  nonhalo_edge_nodes_pt.push_back(first_node_pt);
42724 
42725  // Store the info. of the element used to create these edges
42726  std::pair<Node*, Node*> edge1 = std::make_pair(first_node_pt,
42727  second_node_pt);
42728  nonhalo_edge_element_pt[edge1] = current_ele_pt;
42729 
42730  std::pair<Node*, Node*> edge2 = std::make_pair(second_node_pt,
42731  third_node_pt);
42732  nonhalo_edge_element_pt[edge2] = current_ele_pt;
42733 
42734  std::pair<Node*, Node*> edge3 = std::make_pair(third_node_pt,
42735  first_node_pt);
42736  nonhalo_edge_element_pt[edge3] = current_ele_pt;
42737  }
42738  else
42739  {
42740  // Store the edges
42741  halo_edge_nodes_pt.push_back(first_node_pt);
42742  halo_edge_nodes_pt.push_back(second_node_pt);
42743 
42744  halo_edge_nodes_pt.push_back(second_node_pt);
42745  halo_edge_nodes_pt.push_back(third_node_pt);
42746 
42747  halo_edge_nodes_pt.push_back(third_node_pt);
42748  halo_edge_nodes_pt.push_back(first_node_pt);
42749 
42750  // Store the info. of the element used to create these edges
42751  std::pair<Node*, Node*> edge1 = std::make_pair(first_node_pt,
42752  second_node_pt);
42753  halo_edge_element_pt[edge1] = current_ele_pt;
42754 
42755  std::pair<Node*, Node*> edge2 = std::make_pair(second_node_pt,
42756  third_node_pt);
42757  halo_edge_element_pt[edge2] = current_ele_pt;
42758 
42759  std::pair<Node*, Node*> edge3 = std::make_pair(third_node_pt,
42760  first_node_pt);
42761  halo_edge_element_pt[edge3] = current_ele_pt;
42762  }
42763 
42764  } // for (e < nshared_bound_ele)
42765 
42766  // Filter the edges that give rise to a shared boundary
42767 
42768  // Mark the done edges
42769  std::map<std::pair<Node*,Node*>, bool> edge_done;
42770 
42771  // Storage for the edges shared by the elements
42772  Vector<std::pair<Node*, Node*> > unsorted_edges;
42773 
42774  // Storage for the elements that created the unsorted edges (two
42775  // elements, one at each side of the shared boundary)
42776  Vector<Vector<FiniteElement*> > unsorted_edges_elements_pt;
42777 
42778  const unsigned nnonhalo_edge_nodes = nonhalo_edge_nodes_pt.size();
42779  for (unsigned i = 0; i < nnonhalo_edge_nodes; i+=2)
42780  {
42781  Vector<Node*> currenti_edge(2);
42782  currenti_edge[0] = nonhalo_edge_nodes_pt[i];
42783  currenti_edge[1] = nonhalo_edge_nodes_pt[i+1];
42784 
42785  // Create the edge (both nodes that make the edge)
42786  std::pair<Node*, Node*> new_edge =
42787  std::make_pair(currenti_edge[0], currenti_edge[1]);
42788 
42789  if (!edge_done[new_edge])
42790  {
42791  const unsigned nhalo_edge_nodes = halo_edge_nodes_pt.size();
42792  for (unsigned j = 0; j < nhalo_edge_nodes; j+=2)
42793  {
42794  Vector<Node*> currentj_edge(2);
42795  currentj_edge[0] = halo_edge_nodes_pt[j];
42796  currentj_edge[1] = halo_edge_nodes_pt[j+1];
42797 
42798  // Comparing pointer of nodes
42799  if (currenti_edge[0] == currentj_edge[0] &&
42800  currenti_edge[1] == currentj_edge[1])
42801  {
42802  // Store the edge in the proper container
42803  unsorted_edges.push_back(new_edge);
42804 
42805  // Get the elements associated with the edges
42806  Vector<FiniteElement*> tmp_edge_element_pt;
42807 
42808  FiniteElement* nonhalo_ele_pt = nonhalo_edge_element_pt[new_edge];
42809  FiniteElement* halo_ele_pt = halo_edge_element_pt[new_edge];
42810 
42811  tmp_edge_element_pt.push_back(nonhalo_ele_pt);
42812  tmp_edge_element_pt.push_back(halo_ele_pt);
42813 
42814  // Store the elements associated with the edge
42815  unsorted_edges_elements_pt.push_back(tmp_edge_element_pt);
42816 
42817  // Mark the edge as done
42818  edge_done[new_edge] = true;
42819 
42820  // Break the loop for (j < nedge_node)
42821  break;
42822 
42823  } // equal edge
42824 
42825  // Comparing pointer of nodes (reversed)
42826  else if (currenti_edge[0] == currentj_edge[1] &&
42827  currenti_edge[1] == currentj_edge[0])
42828  {
42829  // Create the edge (both nodes that make the edge)
42830  std::pair<Node*, Node*> new_edge =
42831  std::make_pair(currenti_edge[0], currenti_edge[1]);
42832 
42833  // Store the edge in the proper container
42834  unsorted_edges.push_back(new_edge);
42835 
42836  // Create the (reversed) edge (both nodes that make the edge)
42837  std::pair<Node*, Node*> rev_new_edge =
42838  std::make_pair(currentj_edge[0], currentj_edge[1]);
42839 
42840  // Get the elements associated with the edge
42841  Vector<FiniteElement*> tmp_edge_element_pt;
42842 
42843  FiniteElement* nonhalo_ele_pt = nonhalo_edge_element_pt[new_edge];
42844  FiniteElement* halo_ele_pt = halo_edge_element_pt[rev_new_edge];
42845 
42846  tmp_edge_element_pt.push_back(nonhalo_ele_pt);
42847  tmp_edge_element_pt.push_back(halo_ele_pt);
42848 
42849  // Store the elements associated with the edge
42850  unsorted_edges_elements_pt.push_back(tmp_edge_element_pt);
42851 
42852  // Mark the edge as done
42853  edge_done[new_edge] = true;
42854 
42855  // Break the loop for (j < nedge_node)
42856  break;
42857 
42858  } // if (equal edge)
42859 
42860  } // for (j < nhalo_edge_nodes)
42861 
42862  } // if (!edge_done[new_edge])
42863 
42864  } // for (i < nnonhalo_edge_nodes)
42865 
42866  // We already have the edges that make the shared boundary (and the
42867  // elements)
42868  // Sort them to create a contiguous boundary
42869 
42870  // Mark the already sorted edges
42871  std::map<std::pair<Node*,Node*>, bool> edge_sorted;
42872 
42873  const unsigned nunsorted_edges = unsorted_edges.size();
42874 
42875 #ifdef PARANOID
42876  // The number of unsorted edges must be the same as the number of
42877  // shared_boundary element / 2
42878  if (nshared_bound_ele / 2 != nunsorted_edges)
42879  {
42880  std::ostringstream error_message;
42881  error_message
42882  << "The number of shared boundary elements (" << nshared_bound_ele
42883  << ") is not the double\nof the number of unsorted edges ("
42884  << nunsorted_edges << ") for the current boundary ("<< b << ")\n\n";
42885  throw OomphLibError(error_message.str(),
42886  "RefineableTriangleMesh::update_shared_curve_after_restart()",
42887  OOMPH_EXCEPTION_LOCATION);
42888  }
42889 #endif
42890 
42891  unsigned nsorted_edges = 0;
42892 
42893  // Storing for the sorting nodes extracted from the edges, and
42894  // then used to update the polyline
42895  std::list<Node*> sorted_nodes;
42896 
42897  // Storing for the edges elements
42898  std::list<FiniteElement*> sorted_edges_elements_pt;
42899 
42900  // Get the root edge
42901  std::pair<Node*,Node*> edge = unsorted_edges[0];
42902  nsorted_edges++;
42903 
42904  // Mark edge as done
42905  edge_sorted[edge] = true;
42906 
42907  // The initial and final node on the list
42908  Node *first_node_pt = edge.first;
42909  Node *last_node_pt = edge.second;
42910 
42911  // Push back on the list the new edge (nodes)
42912  sorted_nodes.push_back(first_node_pt);
42913  sorted_nodes.push_back(last_node_pt);
42914 
42915  // Store the elements for the current edge
42916  sorted_edges_elements_pt.push_back(unsorted_edges_elements_pt[0][0]);
42917  sorted_edges_elements_pt.push_back(unsorted_edges_elements_pt[0][1]);
42918 
42919  // Iterate while the number of sorted edges be less than the number of
42920  // unsorted edges
42921  while (nsorted_edges < nunsorted_edges)
42922  {
42923  // Flag to indicate when a node was added
42924  bool node_added = false;
42925 
42926  // Start from the next edge since we have already added the
42927  // previous one as the initial edge
42928  for (unsigned iedge = 1; iedge < nunsorted_edges; iedge++)
42929  {
42930  edge = unsorted_edges[iedge];
42931 
42932  // If edge not done
42933  if (!edge_sorted[edge])
42934  {
42935  // Get each individual node
42936  Node* left_node_pt = edge.first;
42937  Node* right_node_pt = edge.second;
42938 
42939  if (left_node_pt == first_node_pt)
42940  {
42941  // Push front the new node
42942  sorted_nodes.push_front(right_node_pt);
42943  first_node_pt = right_node_pt;
42944  node_added = true;
42945 
42946  // Store the elements for the current edge
42947  sorted_edges_elements_pt.push_front(
42948  unsorted_edges_elements_pt[iedge][1]);
42949  sorted_edges_elements_pt.push_front(
42950  unsorted_edges_elements_pt[iedge][0]);
42951  }
42952  else if (left_node_pt == last_node_pt)
42953  {
42954  // Push back the new node
42955  sorted_nodes.push_back(right_node_pt);
42956  last_node_pt = right_node_pt;
42957  node_added = true;
42958 
42959  // Store the elements for the current edge
42960  sorted_edges_elements_pt.push_back(
42961  unsorted_edges_elements_pt[iedge][0]);
42962  sorted_edges_elements_pt.push_back(
42963  unsorted_edges_elements_pt[iedge][1]);
42964  }
42965  else if (right_node_pt == first_node_pt)
42966  {
42967  // Push front the new node
42968  sorted_nodes.push_front(left_node_pt);
42969  first_node_pt = left_node_pt;
42970  node_added = true;
42971 
42972  // Store the elements for the current edge
42973  sorted_edges_elements_pt.push_front(
42974  unsorted_edges_elements_pt[iedge][1]);
42975  sorted_edges_elements_pt.push_front(
42976  unsorted_edges_elements_pt[iedge][0]);
42977  }
42978  else if (right_node_pt == last_node_pt)
42979  {
42980  // Push back the new node
42981  sorted_nodes.push_back(left_node_pt);
42982  last_node_pt = left_node_pt;
42983  node_added = true;
42984 
42985  // Store the elements for the current edge
42986  sorted_edges_elements_pt.push_back(
42987  unsorted_edges_elements_pt[iedge][0]);
42988  sorted_edges_elements_pt.push_back(
42989  unsorted_edges_elements_pt[iedge][1]);
42990  }
42991 
42992  if (node_added)
42993  {
42994  // Mark as done only if one of its nodes has been
42995  // added to the list
42996  edge_sorted[edge] = true;
42997  nsorted_edges++;
42998 
42999  // Break the for
43000  break;
43001  }
43002 
43003  } // if (!edge_done[edge])
43004  } // for (iedge < nunsorted_edges)
43005  } // while (nsorted_edges < nunsorted_edges)
43006 
43007  // At this point we already have a sorted list of nodes, get the
43008  // vertices from them and store them in a vector container
43009 
43010  // Get the number of nodes on the list
43011  unsigned nvertex = sorted_nodes.size();
43012  // The vector to store the vertices (assign space)
43013  Vector<Vector<double> > polyline_vertices(nvertex);
43014 
43015  // Copy the vertices of the nodes
43016  unsigned counter = 0;
43017  for (std::list<Node*>::iterator it_nodes = sorted_nodes.begin();
43018  it_nodes != sorted_nodes.end();
43019  it_nodes++)
43020  {
43021  polyline_vertices[counter].resize(2);
43022  polyline_vertices[counter][0] = (*it_nodes)->x(0);
43023  polyline_vertices[counter][1] = (*it_nodes)->x(1);
43024  counter++;
43025  }
43026 
43027  // Before going to the unrefinement or refinement process check that
43028  // all processors start from the same vertex. Start from the bottom
43029  // left vertex
43030  if (polyline_vertices[nvertex-1][1] < polyline_vertices[0][1])
43031  {
43032  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
43033  }
43034  else if (polyline_vertices[nvertex-1][1] == polyline_vertices[0][1])
43035  {
43036  if (polyline_vertices[nvertex-1][0] < polyline_vertices[0][0])
43037  {
43038  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
43039  }
43040  }
43041 
43042  // Create the polyline associated with this edge
43043  TriangleMeshPolyLine *new_polyline_pt =
43044  new TriangleMeshPolyLine(polyline_vertices, b);
43045 
43046  // Get the curve section representation
43047  TriangleMeshCurveSection *curve_section_pt = vector_polyline_pt[pp];
43048 
43049  // Copy the connection information from the old shared polyline
43050  // to the new one
43051  this->copy_connection_information(curve_section_pt, new_polyline_pt);
43052 
43053  //Now update the polyline according to the new vertices but first
43054  //check if the object is allowed to delete the representation
43055  //or if it should be done by other object
43056  bool delete_it_on_destructor = false;
43057 
43058  // Establish the element as being deleted by the destructor of
43059  // the class
43060  std::set<TriangleMeshCurveSection*>::iterator it =
43061  this->Free_curve_section_pt.find(curve_section_pt);
43062 
43063  if (it!=this->Free_curve_section_pt.end())
43064  {
43065  this->Free_curve_section_pt.erase(it);
43066  delete curve_section_pt;
43067  delete_it_on_destructor = true;
43068  }
43069 
43070  // Copy the new representation
43071  vector_polyline_pt[pp] = new_polyline_pt;
43072 
43073  // Get the new curve section representation
43074  TriangleMeshCurveSection *new_curve_section_pt = vector_polyline_pt[pp];
43075 
43076  // Update the Boundary - Polyline map
43077  this->Boundary_curve_section_pt[b] = new_curve_section_pt;
43078 
43079  if (delete_it_on_destructor)
43080  {
43081  this->Free_curve_section_pt.insert(new_curve_section_pt);
43082  }
43083 
43084  } // for (pp < npoly)
43085 
43086 }
43087 
43088 //===================================================================
43089 // \short Fill the boundary elements structures when dealing with
43090 // shared boundaries that overlap internal boundaries. Document the
43091 // number of elements on the shared boundaries that go to internal
43092 // boundaries
43093 //===================================================================
43094 template <class ELEMENT>
43097 {
43098  // Dummy file
43099  std::ofstream some_file;
43100  fill_boundary_elements_and_nodes_for_internal_boundaries(some_file);
43101 }
43102 
43103 //===================================================================
43104 // \short Fill the boundary elements structures when dealing with
43105 // shared boundaries that overlap internal boundaries
43106 //===================================================================
43107 template <class ELEMENT>
43110  std::ofstream& outfile)
43111 {
43112  // Get the number of processors
43113  const unsigned nproc = this->communicator_pt()->nproc();
43114  // Get the rank of the current processor
43115  unsigned my_rank = this->communicator_pt()->my_rank();
43116 
43117  // Temporal name for the shared boundary overlaps structure
43118  std::map<unsigned, unsigned> shd_bnd_over_int_bnd =
43119  this->Shared_boundary_overlaps_internal_boundary;
43120 
43121  // Register the internal boundary elements that where found to be
43122  // overlapped by shared boundaries
43123  std::set<unsigned> internal_boundary_overlaped;
43124 
43125  // Document the number of elements and nodes associated to the
43126  // boundaries before filling elements and nodes
43127  if (outfile.is_open())
43128  {
43129  const unsigned nbound = this->nboundary();
43130  outfile << "Number of boundaries: " << nbound << "\n\n";
43131  outfile << "Number of elements and nodes associated to each "
43132  << "boundary before\nfilling elements and nodes\n\n";
43133  for (unsigned i = 0; i < nbound; i++)
43134  {
43135  outfile << "Boundary (" << i << ") Elements ("
43136  << this->nboundary_element(i) << ") " << "Nodes ("
43137  << this->nboundary_node(i) << ")\n";
43138  }
43139  }
43140 
43141  // Storage for the shared boundaries in this processor
43142  std::set<unsigned> shared_boundaries_in_this_processor;
43143 
43144  // Get the shared boundaries that this processor has with other
43145  // processors
43146  for (unsigned iproc = 0; iproc < nproc; iproc++)
43147  {
43148  // Work with other processors only
43149  if (iproc != my_rank)
43150  {
43151  // Get the number of boundaries shared with the "iproc"-th processor
43152  unsigned nshared_boundaries_with_iproc =
43153  this->nshared_boundaries(my_rank, iproc);
43154 
43155  if (nshared_boundaries_with_iproc > 0)
43156  {
43157  // Get the boundaries ids shared with "iproc"-th processor
43158  Vector<unsigned> bound_shared_with_iproc;
43159  bound_shared_with_iproc = this->shared_boundaries_ids(my_rank,
43160  iproc);
43161 
43162  // Loop over shared boundaries with "iproc"-th processor
43163  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
43164  {
43165  unsigned bnd_id = bound_shared_with_iproc[bs];
43166  shared_boundaries_in_this_processor.insert(bnd_id);
43167  }
43168  }
43169  }
43170  }
43171 
43172  // ------------------------------------------------------------------
43173  // Copy the boundary elements and nodes from the shared boundary to
43174  // the internal boundary it overlaps
43175  // ------------------------------------------------------------------
43176  // Go through the shared boundaries that overlap internal boundaries
43177  for (std::map<unsigned, unsigned>::iterator it =
43178  shd_bnd_over_int_bnd.begin(); it != shd_bnd_over_int_bnd.end(); it++)
43179  {
43180  // The shared boundary id that overlaps with an internal boundary
43181  const unsigned shd_bnd_id = (*it).first;
43182  // The internal boundary overlapped by the shared boundary
43183  const unsigned int_bnd_id = (*it).second;
43184 
43185  // Check if the shared boundary exist in this processor
43186  std::set<unsigned>::iterator it_set =
43187  shared_boundaries_in_this_processor.find(shd_bnd_id);
43188  if (it_set != shared_boundaries_in_this_processor.end())
43189  {
43190  internal_boundary_overlaped.insert(int_bnd_id);
43191 
43192  // -----------------------------------------------------------------
43193  // First work the nodes of the shared boundaries that should be
43194  // added to the internal boundaries
43195  const unsigned nbnd_node_shd_bnd = this->nboundary_node(shd_bnd_id);
43196 
43197  // Document the number of nodes that will be passed to the internal
43198  // boundary from the current shared boundary
43199  if (outfile.is_open())
43200  {
43201  outfile << "\nPass info. from shared (" << shd_bnd_id
43202  << ") to internal (" << int_bnd_id << ")\n";
43203  outfile << "Number of shared boundary nodes: "
43204  << nbnd_node_shd_bnd << "\n";
43205  }
43206 
43207  for (unsigned in = 0; in < nbnd_node_shd_bnd; in++)
43208  {
43209  // Get the boundary node
43210  Node* bnd_node_pt = this->boundary_node_pt(shd_bnd_id, in);
43211  // Add the node to the internal boundary
43212  this->add_boundary_node(int_bnd_id, bnd_node_pt);
43213  }
43214 
43215  // -----------------------------------------------------------------
43216  // Second work the boundary elements
43217  // Get the number of boundary elements that should be copied to the
43218  // internal boundary
43219  const unsigned nbnd_ele_shd_bnd = this->nboundary_element(shd_bnd_id);
43220 
43221  // Document the number of elements that will be passed to the
43222  // internal boundary from the current shared boundary
43223  if (outfile.is_open())
43224  {
43225  outfile << "Number of shared boundary elements: "
43226  << nbnd_ele_shd_bnd << "\n\n";
43227  }
43228 
43229  // Go through the boundary elements in the shrared boundary and add
43230  // them to the boundary elements of the internal boundary
43231  for (unsigned ie = 0; ie < nbnd_ele_shd_bnd; ie++)
43232  {
43233  // Get the boundary element
43234  FiniteElement* bnd_ele_pt = this->boundary_element_pt(shd_bnd_id, ie);
43235  // Add the element to the boundary elements storage of the
43236  // internal boundary
43237  Boundary_element_pt[int_bnd_id].push_back(bnd_ele_pt);
43238  // Get the face index of the boundary
43239  int face_index = this->face_index_at_boundary(shd_bnd_id, ie);
43240  // Add the face index to the storage of the boundary
43241  Face_index_at_boundary[int_bnd_id].push_back(face_index);
43242 
43243  } // for (ie < nbnd_ele_shd_bnd)
43244 
43245  // If there are regions we need to fill the storage for regions too
43246  const unsigned nregions = this->nregion();
43247  if (nregions > 1)
43248  {
43249  for (unsigned ir = 0 ; ir < nregions; ir++)
43250  {
43251  // Get the region attribute
43252  const unsigned region_id =
43253  static_cast<unsigned>(this->Region_attribute[ir]);
43254 
43255  // Loop over all elements on boundaries in region ir
43256  const unsigned nele_ir = this->nboundary_element_in_region(shd_bnd_id,
43257  region_id);
43258  for (unsigned ier = 0; ier < nele_ir; ier++)
43259  {
43260  // Get the boundary element in current region
43261  FiniteElement* bnd_ele_pt =
43262  this->boundary_element_in_region_pt(shd_bnd_id, region_id, ier);
43263  // Add the boundary element to the internal boundary in the
43264  // region
43265  this->Boundary_region_element_pt[int_bnd_id][region_id].
43266  push_back(bnd_ele_pt);
43267 
43268  // Get the face index of the boundary
43269  int face_index =
43270  this->face_index_at_boundary_in_region(shd_bnd_id, region_id, ier);
43271  // Add the face index to the storage of the boundary region
43272  this->Face_index_region_at_boundary[int_bnd_id][region_id].
43273  push_back(face_index);
43274 
43275  } // for (ier < nele_ir)
43276 
43277  } // for (ir < nregions)
43278 
43279  } // if (nregions > 1)
43280 
43281  } // if (the shared boundary appears in the current processor)
43282 
43283  } // for (loop over the shared bound that overlap an internal bound)
43284 
43285  // Document the number of elements and nodes associated to the
43286  // boundaries after filling elements and nodes
43287  if (outfile.is_open())
43288  {
43289  const unsigned nbound = this->nboundary();
43290  outfile << "Number of boundaries: " << nbound << "\n\n";
43291  outfile << "Number of elements and nodes associated to each "
43292  << "boundary after\nfilling elements and nodes\n\n";
43293  for (unsigned i = 0; i < nbound; i++)
43294  {
43295  outfile << "Boundary (" << i << ") Elements ("
43296  << this->nboundary_element(i) << ")" << " Nodes ("
43297  << this->nboundary_node(i) << ")\n";
43298  }
43299  }
43300 
43301  // ------------------------------------------------------------------
43302  // Finally, re-setup the boundary coordinates for the new nodes on
43303  // the overlaped internal boundaries
43304  // ------------------------------------------------------------------
43305  for (std::set<unsigned>::iterator it = internal_boundary_overlaped.begin();
43306  it != internal_boundary_overlaped.end(); it++)
43307  {
43308  const unsigned overlaped_internal_bnd_id = (*it);
43309 
43310  // Re-setup boundary coordinates
43311  this->template setup_boundary_coordinates<ELEMENT>(overlaped_internal_bnd_id);
43312  }
43313 
43314 }
43315 
43316 #endif // #ifdef OOMPH_HAS_MPI
43317 
43318  //======================================================================
43319  /// Move the boundary nodes onto the boundary defined by the old mesh
43320  //======================================================================
43321  template <class ELEMENT>
43323  RefineableTriangleMesh<ELEMENT>* &new_mesh_pt, const unsigned &b)
43324  {
43325 
43326  // Quick return
43327  if (!Boundary_coordinate_exists[b])
43328  {
43329  return;
43330  }
43331 
43332  //Firstly we set the boundary coordinates of the new nodes
43333  //In case the mapping between the geometric object's intrinsic coordinate
43334  //and the arc-length coordinate is nonlinear. This is only an approximation,
43335  //but it will ensure that the nodes that were input to triangle will
43336  //retain exactly the same boundary coordinates and then linear interpolation
43337  //is used between those values for any newly created nodes.
43338 
43339  // We need to get the boundary nodes from the boundary face
43340  // elements since the "multi_domain" methods add nodes to the
43341  // "Boundary_node_pt" structure which have no boundary coordinates
43342  // assigned
43343  std::set<Node*> tmp_boundary_node_pt;
43344  const unsigned nboundary_ele = this->nboundary_element(b);
43345  for (unsigned e = 0; e < nboundary_ele; e++)
43346  {
43347  // Get the boundary bulk element
43348  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
43349 #ifdef OOMPH_HAS_MPI
43350  // Only work with nonhalo elements if the mesh is distributed
43351  if (!bulk_ele_pt->is_halo())
43352  {
43353 #endif
43354  // Get the face index
43355  int face_index = this->face_index_at_boundary(b, e);
43356  // Create the face element
43357  FiniteElement* face_ele_pt = new DummyFaceElement<ELEMENT> (
43358  bulk_ele_pt, face_index);
43359 
43360  // Get the number of nodes on the face element
43361  const unsigned nnodes = face_ele_pt->nnode();
43362  for (unsigned i = 0; i < nnodes; i++)
43363  {
43364  // Get the nodes in the face elements
43365  Node* tmp_node_pt = face_ele_pt->node_pt(i);
43366  // Add the nodes to the set of boundary nodes
43367  tmp_boundary_node_pt.insert(tmp_node_pt);
43368  } // for (i < nnodes)
43369 
43370  // Free the memory allocated for the face element
43371  delete face_ele_pt;
43372  face_ele_pt = 0;
43373 #ifdef OOMPH_HAS_MPI
43374  } // if (!bulk_ele_pt->is_halo())
43375 #endif
43376 
43377  } // for (e < nboundary_ele)
43378 
43379  // Get the number of boundary nodes
43380  const unsigned long n_boundary_node = tmp_boundary_node_pt.size();
43381 
43382  // Quick return if there are no nodes
43383  if (n_boundary_node==0)
43384  {
43385 #ifdef OOMPH_HAS_MPI
43386  // Check if we are working with a distributed mesh
43387  if (!this->is_mesh_distributed())
43388  {
43389 #endif
43390  return;
43391 #ifdef OOMPH_HAS_MPI
43392  }
43393  else // The mesh is distributed !!!
43394  {
43395  // Do not forget to participate in the communication
43396  Mesh* face_mesh_pt = new Mesh();
43397  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43398  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
43399 
43400  //Delete the allocated memory for the geometric object and face mesh
43401  delete mesh_geom_obj_pt;
43402 
43403  // Flush the nodes from the face mesh to make sure we
43404  // don't delete them (the bulk mesh still needs them!)
43405  face_mesh_pt->flush_node_storage();
43406  delete face_mesh_pt;
43407  return;
43408  }
43409 #endif
43410  } // if (n_boundary_node==0)
43411 
43412  //Create a vector of existing boundary nodes with their boundary
43413  //coordinate as the first entry so that we can use standard sort algorithms
43414  Vector<double> node_coord(3);
43415  Vector<double> b_coord(1);
43416 
43417  Vector<Vector<double> > old_boundary_node(n_boundary_node);
43418  unsigned tmp_counter = 0;
43419  for(std::set<Node*>::iterator it_node = tmp_boundary_node_pt.begin();
43420  it_node != tmp_boundary_node_pt.end(); it_node++, tmp_counter++)
43421  {
43422  Node* nod_pt = (*it_node);
43423  nod_pt->get_coordinates_on_boundary(b,b_coord);
43424  node_coord[0] = b_coord[0];
43425  node_coord[1] = nod_pt->x(0);
43426  node_coord[2] = nod_pt->x(1);
43427  old_boundary_node[tmp_counter] = node_coord;
43428  } // for (it_node != tmp_boundary_node_pt.end())
43429 
43430  //Sort the vector
43431  std::sort(old_boundary_node.begin(),old_boundary_node.end());
43432 
43433  //Set up an equivalent ordered vector for the new nodes, based on the
43434  //current coordinate which is the scaled arc-length.
43435  //Also provide storage for the original node index,
43436  //the mapped coordinate and a flag to indicate whether the mapped
43437  //coordinate has been assigned.
43438  //Get the nodes on the boundary but consider to which segment (which
43439  //may appear in a distributed mesh) they belong
43440  Vector<Vector<Node*> > segment_nodes_pt;
43441 
43442 #ifdef OOMPH_HAS_MPI
43443  // Get the number of segments
43444  const unsigned nsegments = new_mesh_pt->nboundary_segment(b);
43445 #else
43446  // The number of segments is one since the boundary is not split
43447  // over multiple processors
43448  const unsigned nsegments = 1;
43449 #endif // #ifdef OOMPH_HAS_MPI
43450 
43451 #ifdef OOMPH_HAS_MPI
43452  // Get the total number of nodes on the boundary
43453  const unsigned n_new_boundary_node = new_mesh_pt->nboundary_segment_node(b);
43454 
43455  // Check if we are working with a distributed mesh
43456  if (this->is_mesh_distributed())
43457  {
43458  // If that is the case we need to ensure that the new mesh has
43459  // nodes too, if that is not the case then return
43460  // Quick return if there are no nodes
43461  if (n_new_boundary_node==0)
43462  {
43463  // Do not forget to participate in the communication
43464  Mesh* face_mesh_pt = new Mesh();
43465  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43466  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
43467 
43468  //Delete the allocated memory for the geometric object and face mesh
43469  delete mesh_geom_obj_pt;
43470  // Flush the nodes from the face mesh to make sure we
43471  // don't delete them (the bulk mesh still needs them!)
43472  face_mesh_pt->flush_node_storage();
43473  delete face_mesh_pt;
43474  return;
43475  }
43476  }
43477 #endif // #ifdef OOMPH_HAS_MPI
43478 
43479  //Create a vector of boundary nodes that must be moved
43480  Vector<Vector<unsigned> > nodes_to_be_snapped(nsegments);
43481 
43482  // Go through all the segments to assign the snapped zeta coordinates
43483  // for the new nodes
43484  for (unsigned is = 0; is < nsegments; is++)
43485  {
43486 #ifdef OOMPH_HAS_MPI
43487  const unsigned n_new_boundary_segment_node =
43488  new_mesh_pt->nboundary_segment_node(b,is);
43489 #else
43490  const unsigned n_new_boundary_segment_node = new_mesh_pt->nboundary_node(b);
43491 #endif // #ifdef OOMPH_HAS_MPI
43492 
43493  Vector<Vector<double> > new_boundary_node(n_new_boundary_segment_node);
43494  //There will be six data associated with each node
43495  node_coord.resize(6,0.0);
43496  for(unsigned n = 0; n < n_new_boundary_segment_node; n++)
43497  {
43498 #ifdef OOMPH_HAS_MPI
43499  Node* nod_pt = new_mesh_pt->boundary_segment_node_pt(b,is,n);
43500 #else
43501  Node* nod_pt = new_mesh_pt->boundary_node_pt(b,n);
43502 #endif // #ifdef OOMPH_HAS_MPI
43503  nod_pt->get_coordinates_on_boundary(b,b_coord);
43504  node_coord[0] = b_coord[0];
43505  node_coord[1] = nod_pt->x(0);
43506  node_coord[2] = nod_pt->x(1);
43507  node_coord[3] = n;
43508  new_boundary_node[n] = node_coord;
43509  } // for (n < n_new_boundary_segment_node)
43510 
43511  //Sort the new boundary nodes based on their arc-length coordinate
43512  std::sort(new_boundary_node.begin(),new_boundary_node.end());
43513 
43514  //We now have two sets of nodes ordered by a coordinate that acts in the
43515  //same direction and has the same limits.
43516 
43517  //Loop over the vector of new nodes and allocate exactly the same
43518  //coordinate as the old nodes at points of coincidence
43519  unsigned old_index = 0;
43520  for(unsigned n=0;n<n_new_boundary_segment_node;++n)
43521  {
43522  //Loop over the set of old nodes and if the x and y coordinates
43523  //coincide with the new node copy accross the new boundary coordinate
43524  for(unsigned m=old_index;m<n_boundary_node;++m)
43525  {
43526  if(
43527  (std::fabs(old_boundary_node[m][1]-new_boundary_node[n][1])<1.0e-14)
43528  &&
43529  (std::fabs(old_boundary_node[m][2]-new_boundary_node[n][2])<1.0e-14))
43530  {
43531  //Store the boundary coordinate from the old mesh
43532  new_boundary_node[n][4] = old_boundary_node[m][0];
43533  //Say that it has been stored
43534  new_boundary_node[n][5] = 1.0;
43535  //For efficiency, we can start the iteration from here next
43536  //time round because both vectors are ordered
43537  old_index = m;
43538  break;
43539  }
43540  }
43541  }
43542 
43543  //Check that the end-points have new boundary coordinates allocated
43544 #ifdef PARANOID
43545  if((new_boundary_node[0][5]==0.0) ||
43546  (new_boundary_node[n_new_boundary_segment_node-1][5] == 0.0))
43547  {
43548  std::ostringstream error_stream;
43549  error_stream
43550  <<"New boundary coordinates not found for the first and/or last "
43551  <<"nodes\n"
43552  <<"on the boundary " << b << ". This should not happen because "
43553  <<"these\nlimits should have been setup in the constructor\n";
43554  error_stream
43555  <<"The distance between the new and old nodes is probably outside\n"
43556  <<"our tolerance.\n";
43557  error_stream.precision(20);
43558  error_stream << "Old boundaries: \n";
43559  error_stream <<
43560  old_boundary_node[0][1] << " " << old_boundary_node[0][2]
43561  << " : " <<
43562  old_boundary_node[n_boundary_node-1][1] << " " <<
43563  old_boundary_node[n_boundary_node-1][2] << "\n";
43564  error_stream << "New boundaries: \n" <<
43565  new_boundary_node[0][1] << " " << new_boundary_node[0][2] << " : " <<
43566  new_boundary_node[n_new_boundary_segment_node-1][1] << " " <<
43567  new_boundary_node[n_new_boundary_segment_node-1][2] << "\n";
43568  OomphLibWarning(error_stream.str(),
43569  "RefineableTriangleMesh::snap_nodes_onto_boundary()",
43570  OOMPH_EXCEPTION_LOCATION);
43571  }
43572 #endif
43573 
43574  // This is only true if the boundary is not splitted among the
43575  // processors
43576  if (!this->is_mesh_distributed())
43577  {
43578  //The end points should always be present, so we
43579  //can (and must) always add them in exactly
43580  new_boundary_node[0][4] = new_boundary_node[0][0];
43581 
43582  /// Correct!? Because assigned again below
43583  new_boundary_node[n_new_boundary_segment_node-1][4] =
43584  new_boundary_node[0][5] = 1.0;
43585 
43586  new_boundary_node[n_new_boundary_segment_node-1][4] =
43587  new_boundary_node[n_new_boundary_segment_node-1][0];
43588  new_boundary_node[n_new_boundary_segment_node-1][5] = 1.0;
43589  }
43590 
43591  //Now loop over the interior nodes again and
43592  //use linear interpolation to fill in any unassigned coordiantes
43593  for(unsigned n=1;n<n_new_boundary_segment_node-1;++n)
43594  {
43595  //If the new boundary coordinate has NOT been allocated
43596  if(new_boundary_node[n][5]==0.0)
43597  {
43598  //Add its (unsorted) node number to the list
43599  nodes_to_be_snapped[is].push_back(
43600  static_cast<unsigned>(new_boundary_node[n][3]));
43601 
43602  //We assume that the previous nodal value has been assigned
43603  //and read out the old and new boundary coordinates
43604  double zeta_old_low = new_boundary_node[n-1][0];
43605  double zeta_new_low = new_boundary_node[n-1][4];
43606 
43607  //Loop over the nodes above the current node until
43608  //we find the next one that has been allocated
43609  for(unsigned m=n+1;m<n_new_boundary_segment_node;++m)
43610  {
43611  if(new_boundary_node[m][5]==1.0)
43612  {
43613  //Read out the old boundary coordinate
43614  double zeta_old_high = new_boundary_node[m][0];
43615  double zeta_new_high = new_boundary_node[m][4];
43616  //Use linear interpolation to assign the new boundary coordinate
43617  double frac = (new_boundary_node[n][0] - zeta_old_low)/
43618  (zeta_old_high - zeta_old_low);
43619  new_boundary_node[n][4] = zeta_new_low
43620  + frac*(zeta_new_high - zeta_new_low);
43621  new_boundary_node[n][5] = 1.0;
43622  break;
43623  }
43624  }
43625  }
43626  }
43627 
43628  //Loop over all the nodes and set the new boundary coordinate
43629  for(unsigned n=0;n<n_new_boundary_segment_node;++n)
43630  {
43631  if(new_boundary_node[n][5]==0)
43632  {
43633  throw OomphLibError(
43634  "New boundary coordinate not assigned\n",
43635  "RefineableTriangleMesh::snap_nodes_onto_boundary()",
43636  OOMPH_EXCEPTION_LOCATION);
43637  }
43638 
43639 #ifdef OOMPH_HAS_MPI
43640  //get the old coordinate
43641  new_mesh_pt->boundary_segment_node_pt(
43642  b,is,static_cast<unsigned>(new_boundary_node[n][3]))
43643  ->get_coordinates_on_boundary(b,b_coord);
43644  //Set the new coordinate
43645  b_coord[0] = new_boundary_node[n][4];
43646  new_mesh_pt->boundary_segment_node_pt(
43647  b,is,static_cast<unsigned>(new_boundary_node[n][3]))
43648  ->set_coordinates_on_boundary(b,b_coord);
43649 #else
43650  //get the old coordinate
43651  new_mesh_pt->boundary_node_pt(
43652  b,static_cast<unsigned>(new_boundary_node[n][3]))
43653  ->get_coordinates_on_boundary(b,b_coord);
43654  //Set the new coordinate
43655  b_coord[0] = new_boundary_node[n][4];
43656  new_mesh_pt->boundary_node_pt(
43657  b,static_cast<unsigned>(new_boundary_node[n][3]))
43658  ->set_coordinates_on_boundary(b,b_coord);
43659 #endif // #ifdef OOMPH_HAS_MPI
43660 
43661  }
43662 
43663  } // for (is < nsegments)
43664 
43665  Mesh* face_mesh_pt = new Mesh();
43666  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43667 
43668  //Now that the coordinates have been set up we can do the snapping
43669  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt);
43670 
43671  //Now assign the new nodes positions based on the old meshes
43672  //potentially curvilinear boundary (its geom object incarnation)
43673  Vector<double> new_x(2);
43674 
43675  //Loop over the nodes that need to be snapped
43676  for(unsigned is = 0; is < nsegments; is++)
43677  {
43678  const unsigned nnodes_to_snap = nodes_to_be_snapped[is].size();
43679 
43680  for (unsigned in = 0; in < nnodes_to_snap; in++)
43681  {
43682  //Read out the boundary node number
43683  unsigned n = nodes_to_be_snapped[is][in];
43684 #ifdef OOMPH_HAS_MPI
43685  //Get the boundary coordinate of all new nodes
43686  Node* const nod_pt = new_mesh_pt->boundary_segment_node_pt(b,is,n);
43687 #else
43688  //Get the boundary coordinate of all new nodes
43689  Node* const nod_pt = new_mesh_pt->boundary_node_pt(b,n);
43690 #endif // #ifdef OOMPH_HAS_MPI
43691 
43692  nod_pt->get_coordinates_on_boundary(b,b_coord);
43693  //Let's find boundary coordinates of the new node
43694  mesh_geom_obj_pt->position(b_coord,new_x);
43695 
43696  //Now snap to the boundary
43697  for(unsigned i=0;i<2;i++)
43698  {
43699  nod_pt->x(i) = new_x[i];
43700  }
43701  }
43702  }
43703 
43704  //Delete the allocated memory for the geometric object and face mesh
43705  delete mesh_geom_obj_pt;
43706  // Flush the nodes from the face mesh to make sure we
43707  // don't delete them (the bulk mesh still needs them!)
43708  face_mesh_pt->flush_node_storage();
43709  delete face_mesh_pt;
43710 
43711  //Fix up the elements adjacent to the boundary
43712 
43713  // Dummy six node element for sorting out bubble node for
43714  // seven node enriched quadratic triangles
43715  TElement<2,3> dummy_six_node_element;
43716  for (unsigned j=0;j<6;j++)
43717  {
43718  dummy_six_node_element.construct_node(j);
43719  }
43720 
43721  //This should definitely become a triangular element member function
43722  //Loop over elements
43723  unsigned n_bound_el = new_mesh_pt->nboundary_element(b);
43724  for(unsigned e=0;e<n_bound_el;e++)
43725  {
43726  FiniteElement* el_pt = new_mesh_pt->boundary_element_pt(b,e);
43727 
43728  // Deal with different numbers of nodes separately
43729  unsigned nnod=el_pt->nnode();
43730 
43731 // #ifdef PARANOID
43732 // // Flag to indicate if we successully classified/dealt with the element
43733 // bool success=false;
43734 // #endif
43735 
43736  // Simplex element: Nothing to be done other than error checking
43737  if (nnod==3)
43738  {
43739 #ifdef PARANOID
43740  // Try to cast to a simplex element
43741  TElement<2,2>* t_el_pt=dynamic_cast<TElement<2,2>*>(el_pt);
43742  if (t_el_pt==0)
43743  {
43744  throw OomphLibError(
43745  "Have a three-noded element that's not a TElement<2,2>",
43746  OOMPH_CURRENT_FUNCTION,
43747  OOMPH_EXCEPTION_LOCATION);
43748  }
43749  // If I get there I must not have thrown :)
43750  //success=true;
43751 #endif
43752  }
43753  // Quadratic element (or enriched quadratic)
43754 
43755  else if ((nnod==6)||(nnod==7))
43756  {
43757 
43758 #ifdef PARANOID
43759  // Try to cast to a quadratic element
43760  TElement<2,3>* t_el_pt=dynamic_cast<TElement<2,3>*>(el_pt);
43761  if (t_el_pt==0)
43762  {
43763  if (nnod==6)
43764  {
43765  throw OomphLibError(
43766  "Have a six-noded element that's not a TElement<2,3>",
43767  OOMPH_CURRENT_FUNCTION,
43768  OOMPH_EXCEPTION_LOCATION);
43769  }
43770  else
43771  {
43772  throw OomphLibError(
43773  "Have a seven-noded element that's not a TElement<2,3>",
43774  OOMPH_CURRENT_FUNCTION,
43775  OOMPH_EXCEPTION_LOCATION);
43776  }
43777  }
43778  // If I get there I must not have thrown :)
43779  //success=true;
43780 #endif
43781  // Deal with six noded stuff for all (normal and enriched) elements
43782 
43783  ///----------------------------------------------------------------
43784  /// Repositioning of mid-side nodes
43785  ///----------------------------------------------------------------
43786 
43787  //Side between 0 and 1
43788  if(el_pt->node_pt(3)->is_on_boundary(b))
43789  {
43790  //Make sure that the node I'm about to move is NOT on
43791  //a boundary
43792  if(!el_pt->node_pt(5)->is_on_boundary())
43793  {
43794  //Reset the internal nodes
43795  for(unsigned i=0;i<2;i++)
43796  {
43797  el_pt->node_pt(5)->x(i) =
43798  0.5*(el_pt->node_pt(0)->x(i) + el_pt->node_pt(2)->x(i));
43799  }
43800  }
43801  //Make sure that the node I'm about to move is NOT on
43802  //a boundary
43803  if(!el_pt->node_pt(4)->is_on_boundary())
43804  {
43805  //Reset the internal nodes
43806  for(unsigned i=0;i<2;i++)
43807  {
43808  el_pt->node_pt(4)->x(i) =
43809  0.5*(el_pt->node_pt(1)->x(i) + el_pt->node_pt(2)->x(i));
43810  }
43811  }
43812  }
43813 
43814  //Side between 1 and 2
43815  if(el_pt->node_pt(4)->is_on_boundary(b))
43816  {
43817  //Make sure that the node I'm about to move is NOT on
43818  //a boundary
43819  if(!el_pt->node_pt(5)->is_on_boundary())
43820  {
43821  //Reset the internal nodes
43822  for(unsigned i=0;i<2;i++)
43823  {
43824  el_pt->node_pt(5)->x(i) =
43825  0.5*(el_pt->node_pt(0)->x(i) + el_pt->node_pt(2)->x(i));
43826  }
43827  }
43828  //Make sure that the node I'm about to move is NOT on
43829  //a boundary
43830  if(!el_pt->node_pt(3)->is_on_boundary())
43831  {
43832  //Reset the internal nodes
43833  for(unsigned i=0;i<2;i++)
43834  {
43835  el_pt->node_pt(3)->x(i) =
43836  0.5*(el_pt->node_pt(0)->x(i) + el_pt->node_pt(1)->x(i));
43837  }
43838  }
43839  }
43840 
43841  //Side between 0 and 2
43842  if(el_pt->node_pt(5)->is_on_boundary(b))
43843  {
43844  //Make sure that the node I'm about to move is NOT on
43845  //a boundary
43846  if(!el_pt->node_pt(4)->is_on_boundary())
43847  {
43848  //Reset the internal nodes
43849  for(unsigned i=0;i<2;i++)
43850  {
43851  el_pt->node_pt(4)->x(i) =
43852  0.5*(el_pt->node_pt(1)->x(i) + el_pt->node_pt(2)->x(i));
43853  }
43854  }
43855  //Make sure that the node I'm about to move is NOT on
43856  //a boundary
43857  if(!el_pt->node_pt(3)->is_on_boundary())
43858  {
43859  //Reset the internal nodes
43860  for(unsigned i=0;i<2;i++)
43861  {
43862  el_pt->node_pt(3)->x(i) =
43863  0.5*(el_pt->node_pt(0)->x(i) + el_pt->node_pt(1)->x(i));
43864  }
43865  }
43866  }
43867 
43868  // If it's seven noded it's likely to be an enriched one: Deal with
43869  // the central (bubble) node
43870  if (nnod==7)
43871  {
43872  // Try to cast to an enriched quadratic element
43873  TBubbleEnrichedElement<2,3>* t_el_pt=
43874  dynamic_cast<TBubbleEnrichedElement<2,3>*>(el_pt);
43875  if (t_el_pt==0)
43876  {
43877  throw OomphLibError(
43878  "Have seven-noded element that's not a TBubbleEnrichedElement<2,3>",
43879  OOMPH_CURRENT_FUNCTION,
43880  OOMPH_EXCEPTION_LOCATION);
43881  }
43882 
43883  // Assign the new non-bubble coordinates to the six noded dummy element
43884  for (unsigned j=0;j<6;j++)
43885  {
43886  for (unsigned i=0;i<2;i++)
43887  {
43888  dummy_six_node_element.node_pt(j)->x(i)=el_pt->node_pt(j)->x(i);
43889  }
43890  }
43891 
43892  // Local coordinate of enriched node
43893  unsigned j_enriched=6;
43894  Vector<double> s(2);
43895  el_pt->local_coordinate_of_node(j_enriched,s);
43896 
43897  // Get its position from non-enriched element
43898  Vector<double> x(2);
43899  dummy_six_node_element.interpolated_x(s,x);
43900  el_pt->node_pt(j_enriched)->x(0) = x[0];
43901  el_pt->node_pt(j_enriched)->x(1) = x[1];
43902  }
43903  }
43904  // Any other case cannot be dealt with at the moment
43905 
43906  else
43907  {
43908  std::ostringstream error_stream;
43909  error_stream
43910  << "Cannot deal with this particular " << nnod
43911  << "-noded element yet.\n"
43912  << "Please implement this yourself.\n";
43913  throw OomphLibError(error_stream.str(),
43914 OOMPH_CURRENT_FUNCTION,
43915  OOMPH_EXCEPTION_LOCATION);
43916  }
43917  }
43918 
43919  // Cleanup
43920  for (unsigned j=0;j<6;j++)
43921  {
43922  delete dummy_six_node_element.node_pt(j);
43923  }
43924 
43925  }
43926 
43927 
43928 
43929 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
43930 
43931 }
43932 
43933 #endif
oomph::Node::get_coordinates_on_boundary
virtual void get_coordinates_on_boundary(const unsigned &b, const unsigned &k, Vector< double > &boundary_zeta)
Return the vector of the k-th generalised boundary coordinates on mesh boundary b....
Definition: nodes.cc:2301
oomph::RefineableTriangleMesh::update_open_curve_using_elements_area
bool update_open_curve_using_elements_area(TriangleMeshOpenCurve *&open_curve_pt, const Vector< double > &target_area)
Updates the open curve but using the elements area instead of the default refinement and unrefinement...
Definition: triangle_mesh.template.cc:38367
oomph::RefineableTriangleMesh::create_polylines_from_polyfiles
void create_polylines_from_polyfiles(const std::string &node_file_name, const std::string &poly_file_name)
Helper function to create polylines and fill associate data.
Definition: triangle_mesh.template.cc:36397
oomph::TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values
void compute_boundary_segments_connectivity_and_initial_zeta_values(const unsigned &b)
Compute the boundary segments connectivity for those boundaries that were splited during the distribu...
Definition: triangle_mesh.template.cc:1846
oomph::TriangulateIO::numberofpoints
int numberofpoints
Definition: unstructured_two_d_mesh_geometry_base.h:75
oomph::BoundaryNodeBase::index_of_first_value_assigned_by_face_element_pt
std::map< unsigned, unsigned > *& index_of_first_value_assigned_by_face_element_pt()
Return pointer to the map giving the index of the first face element value.
Definition: nodes.h:1909
CGALSamplePointContainer
CGAL-based SamplePointContainer.
Definition: sample_point_container.h:1079
oomph::TriangleMeshPolygon::reset_reference_configuration
virtual void reset_reference_configuration()
Virtual function that should be overloaded to update the polygons reference configuration.
Definition: unstructured_two_d_mesh_geometry_base.h:1457
oomph::TriangleMesh::select_boundary_face_elements
void select_boundary_face_elements(Vector< FiniteElement * > &face_el_pt, const unsigned &b, bool &is_internal_boundary, std::map< FiniteElement *, FiniteElement * > &face_to_bulk_element_pt)
Select face element from boundary using the criteria to decide which of the two face elements should ...
Definition: triangle_mesh.template.cc:5245
oomph::oomph_info
OomphInfo oomph_info
Definition: oomph_definitions.cc:326
oomph::RefineableTriangleMesh::reset_halo_haloed_scheme
void reset_halo_haloed_scheme()
In charge of. re-establish the halo(ed) scheme on all processors. Sends info. to create halo elements...
Definition: triangle_mesh.template.cc:15327
oomph::TriangleMeshPolygon::npolyline
unsigned npolyline() const
Number of constituent polylines.
Definition: unstructured_two_d_mesh_geometry_base.h:1369
oomph::TriangleMesh::get_halo_elements_on_all_procs
void get_halo_elements_on_all_procs(const unsigned &nproc, const Vector< unsigned > &element_domain, const Vector< GeneralisedElement * > &backed_up_el_pt, std::map< Data *, std::set< unsigned > > &processors_associated_with_data, const bool &overrule_keep_as_halo_element_status, std::map< GeneralisedElement *, unsigned > &element_to_global_index, Vector< Vector< Vector< GeneralisedElement * > > > &output_halo_elements_pt)
Creates the halo elements on all processors Gets the halo elements on all processors,...
Definition: triangle_mesh.template.cc:11485
oomph::RefineableTriangleMesh::surface_remesh_for_inner_hole_boundaries
virtual bool surface_remesh_for_inner_hole_boundaries(Vector< Vector< double > > &internal_point_coord, const bool &check_only=false)
Generate a new PSLG representation of the inner hole boundaries. Optional boolean is used to run it a...
Definition: triangle_mesh.template.cc:36208
oomph::classcomp::Tol
static double Tol
Definition: triangle_mesh.template.cc:15037
oomph::FiniteElement::node_pt
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2126
oomph::RefineableTriangleMesh::restore_polyline_connections_helper
void restore_polyline_connections_helper(TriangleMeshPolyLine *polyline_pt, Vector< TriangleMeshPolyLine * > &resume_initial_connection_polyline_pt, Vector< TriangleMeshPolyLine * > &resume_final_connection_polyline_pt)
Restore the connections of the specific polyline The vertices numbering on the destination boundaries...
Definition: triangle_mesh.template.cc:33012
oomph::RefineableTriangleMesh::sort_nodes_on_shared_boundaries
void sort_nodes_on_shared_boundaries()
Sort the nodes on shared boundaries so that the processors that share a boundary agree with the order...
Definition: triangle_mesh.template.cc:15131
oomph::RefineableTriangleMesh::update_open_curve_after_restart
void update_open_curve_after_restart(TriangleMeshOpenCurve *&open_curve_pt)
Updates the open curve representation after restart.
Definition: triangle_mesh.template.cc:41735
oomph::RefineableTriangleMesh::update_shared_curve_using_elements_area
bool update_shared_curve_using_elements_area(Vector< TriangleMeshPolyLine * > &vector_polyline_pt, const Vector< double > &target_areas)
Updates the polylines using the elements area as constraint for the number of points along the bounda...
Definition: triangle_mesh.template.cc:39611
oomph::TriangleMeshParameters::internal_open_curves_pt
Vector< TriangleMeshOpenCurve * > internal_open_curves_pt() const
Helper function for getting the internal open boundaries.
Definition: triangle_mesh.template.h:171
level
and code FiniteElement::J_eulerian(...) \endcode returns the Jacobian of the mapping from Eulerian coordinates to local coordinates. - The function \c GeneralisedElement c QElement< 3, 2 > is an node brick element with a trilinear mapping between and global coordinates The dimension and the number of c Nodes must be set by calling the appropriate c set_ functions in the see ref set_commands above The most important member functions implemented at this level include Functions that evaluate the shape in terms of the c FiniteElement s coordinates functions that determine whether a c Node is located at a particular coordinate Output functions that allow the element shapes to be plotted we specify a pointer to a spatial integration the default assignment can be over written at a higher level This is discussed in more detail in a< A HREF="../../optimisation/html/index.html"> separate document</A > subsubsection Maths_Element we implement the equations that are represented by the specific element We implement the employing either the geometric shape functions that already exist on level
Definition: the_data_structure.txt:560
oomph::TriangleMeshOpenCurve::polyline_pt
TriangleMeshPolyLine * polyline_pt(const unsigned &i) const
Pointer to i-th constituent polyline.
Definition: unstructured_two_d_mesh_geometry_base.h:1558
oomph::RefineableTriangleMesh::snap_nodes_onto_boundary
void snap_nodes_onto_boundary(RefineableTriangleMesh< ELEMENT > *&new_mesh_pt, const unsigned &b)
Snap the boundary nodes onto any curvilinear boundaries.
Definition: triangle_mesh.template.cc:43322
NonRefineableBinArray::get_all_bins_content
const std::map< unsigned, Vector< std::pair< FiniteElement *, Vector< double > > > > * get_all_bins_content() const
Get the contents of all bins in vector.
Definition: sample_point_container.h:976
oomph::TriangulateIO::trianglelist
int * trianglelist
Definition: unstructured_two_d_mesh_geometry_base.h:78
oomph::TriangleMeshParameters::internal_closed_curve_pt
Vector< TriangleMeshClosedCurve * > internal_closed_curve_pt() const
Helper function for getting the internal closed boundaries.
Definition: triangle_mesh.template.h:162
oomph::SolidNode::read_values_from_vector
void read_values_from_vector(const Vector< double > &vector_of_values, unsigned &index)
Read all data and time history values from the vector starting from index. On return the index will b...
Definition: nodes.cc:3650
oomph::Data::set_value
void set_value(const unsigned &i, const double &value_)
Set the i-th stored data value to specified value. The only reason that we require an explicit set fu...
Definition: nodes.h:267
oomph::TriangleMeshPolyLine::final_vertex_coordinate
void final_vertex_coordinate(Vector< double > &vertex)
Get last vertex coordinates.
Definition: unstructured_two_d_mesh_geometry_base.h:856
oomph::Multi_domain_functions::Flat_packed_unsigneds
Vector< unsigned > Flat_packed_unsigneds
Vector of flat-packed unsigneds to be communicated with other processors – this is really "private" d...
Definition: multi_domain.cc:124
oomph::TriangleMesh::update_holes_information_helper
void update_holes_information_helper(Vector< TriangleMeshPolygon * > &polygons_pt, Vector< Vector< double > > &output_holes_coordinates)
Keeps those vertices that define a hole, those that are inside closed internal boundaries in the new ...
Definition: triangle_mesh.template.cc:10801
oomph::TElement< 2, 3 >
oomph::TriangleMeshPolygon::polyline_pt
TriangleMeshPolyLine * polyline_pt(const unsigned &i) const
Pointer to i-th constituent polyline.
Definition: unstructured_two_d_mesh_geometry_base.h:1372
oomph::FiniteElement::size
double size() const
Definition: elements.cc:4210
oomph::RefineableTriangleMesh::get_required_nodal_information_load_balance_helper
void get_required_nodal_information_load_balance_helper(Vector< Vector< FiniteElement * > > &f_halo_ele_pt, unsigned &iproc, Node *nod_pt)
Helper function to get the required nodal information from an haloed node so that a fully-functional ...
Definition: triangle_mesh.template.cc:26534
oomph::UnstructuredTwoDMeshGeometryBase::nboundary_element_in_region
unsigned nboundary_element_in_region(const unsigned &b, const unsigned &r) const
Return the number of elements adjacent to boundary b in region r.
Definition: unstructured_two_d_mesh_geometry_base.h:1753
oomph::GeneralisedElement::must_be_kept_as_halo
bool must_be_kept_as_halo() const
Test whether the element must be kept as a halo element.
Definition: elements.h:1175
oomph::RefineableTriangleMesh::create_new_shared_boundaries
void create_new_shared_boundaries(std::set< FiniteElement * > &element_in_processor_pt, Vector< Vector< FiniteElement * > > &new_shared_boundary_element_pt, Vector< Vector< unsigned > > &new_shared_boundary_element_face_index)
Creates the new shared boundaries, this method is also in charge of computing the shared boundaries i...
Definition: triangle_mesh.template.cc:22466
oomph::RefineableTriangleMesh::fill_boundary_elements_and_nodes_for_internal_boundaries
void fill_boundary_elements_and_nodes_for_internal_boundaries()
Definition: triangle_mesh.template.cc:43096
oomph::Node::remove_from_boundary
virtual void remove_from_boundary(const unsigned &b)
Broken interface for removing the node from the mesh boundary b Here to provide error reporting.
Definition: nodes.cc:2272
oomph::TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary
void re_assign_initial_zeta_values_for_internal_boundary(const unsigned &b, Vector< std::list< FiniteElement * > > &old_segment_sorted_ele_pt, std::map< FiniteElement *, bool > &old_is_inverted)
Re-assign the boundary segments initial zeta (arclength) value for those internal boundaries that wer...
Definition: triangle_mesh.template.cc:4063
oomph::OomphCommunicator
An oomph-lib wrapper to the MPI_Comm communicator object. Just contains an MPI_Comm object (which is ...
Definition: communicator.h:57
oomph::RefineableTriangleMesh::get_required_elemental_information_helper
void get_required_elemental_information_helper(unsigned &iproc, FiniteElement *ele_pt)
Helper function to get the required elemental information from an haloed element. This info....
Definition: triangle_mesh.template.cc:17800
oomph::RefineableTriangleMesh::get_required_elemental_information_load_balance_helper
void get_required_elemental_information_load_balance_helper(unsigned &iproc, Vector< Vector< FiniteElement * > > &f_haloed_ele_pt, FiniteElement *ele_pt)
Helper function to get the required elemental information from the element to be sent....
Definition: triangle_mesh.template.cc:26104
oomph::RefineableTriangleMesh::max_element_size
double & max_element_size()
Max element size allowed during adaptation.
Definition: triangle_mesh.template.h:2375
oomph::TriangleMesh::create_tmp_polygons_helper
void create_tmp_polygons_helper(Vector< Vector< TriangleMeshPolyLine * > > &polylines_pt, Vector< TriangleMeshPolygon * > &polygons_pt)
Take the polylines from the shared boundaries and create temporary polygon representations of the dom...
Definition: triangle_mesh.template.cc:8519
oomph::RefineableTriangleMesh::load_balance
void load_balance(const Vector< unsigned > &input_target_domain_for_local_non_halo_element)
Performs the load balancing for unstructured meshes, the load balancing strategy is based on mesh mig...
Definition: triangle_mesh.template.cc:20245
oomph::FiniteElement
A general Finite Element class.
Definition: elements.h:1291
oomph::MeshAsGeomObject::position
void position(const Vector< double > &zeta, Vector< double > &r) const
Return the position as a function of the intrinsic coordinate zeta. This provides an (expensive!...
Definition: mesh_as_geometric_object.h:404
oomph::Node::set_coordinates_on_boundary
virtual void set_coordinates_on_boundary(const unsigned &b, const unsigned &k, const Vector< double > &boundary_zeta)
Set the vector of the k-th generalised boundary coordinates on mesh boundary b. Broken virtual interf...
Definition: nodes.cc:2315
oomph::UnstructuredTwoDMeshGeometryBase::nregion_element
unsigned nregion_element(const unsigned &i)
Return the number of elements in the i-th region.
Definition: unstructured_two_d_mesh_geometry_base.h:1642
oomph::UnstructuredTwoDMeshGeometryBase::region_attribute
double region_attribute(const unsigned &i)
Return the attribute associated with region i.
Definition: unstructured_two_d_mesh_geometry_base.h:1700
oomph::TriangleMeshCurveSection::final_vertex_connected_n_vertex
unsigned final_vertex_connected_n_vertex() const
Sets the vertex number to which the final end is connected.
Definition: unstructured_two_d_mesh_geometry_base.h:464
oomph::RefineableTriangleMesh::reset_shared_boundary_elements_and_nodes
void reset_shared_boundary_elements_and_nodes(const bool flush_elements=true, const bool update_elements=true, const bool flush_nodes=true, const bool update_nodes=true)
Re-establish the shared boundary elements after the adaptation process (the updating of shared nodes ...
Definition: triangle_mesh.template.cc:15241
oomph::OomphLibError
Definition: oomph_definitions.h:229
oomph::Mesh::finite_element_pt
FiniteElement * finite_element_pt(const unsigned &e) const
Upcast (downcast?) to FiniteElement (needed to access FiniteElement member functions).
Definition: mesh.h:477
oomph::RefineableTriangleMesh::refine_boundary
bool refine_boundary(Mesh *face_mesh_pt, Vector< Vector< double > > &vector_bnd_vertices, double &refinement_tolerance, const bool &check_only=false)
Helper function that performs the refinement process on the specified boundary by using the provided ...
Definition: triangle_mesh.template.cc:35133
oomph::Problem::enable_problem_distributed
void enable_problem_distributed()
Enable problem distributed.
Definition: problem.h:966
oomph::Mesh::element_pt
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
Definition: mesh.h:462
oomph::TriangulateIO::numberofregions
int numberofregions
Definition: unstructured_two_d_mesh_geometry_base.h:94
triangle_mesh.template.h
oomph::TriangleMesh::break_loops_on_shared_polyline_helper
void break_loops_on_shared_polyline_helper(const unsigned &initial_shd_bnd_id, std::list< Node * > &input_nodes, Vector< FiniteElement * > &input_boundary_element_pt, Vector< int > &input_face_index_element, const int &input_connect_to_the_left, const int &input_connect_to_the_right, Vector< std::list< Node * > > &output_sorted_nodes_pt, Vector< Vector< FiniteElement * > > &output_boundary_element_pt, Vector< Vector< int > > &output_face_index_element, Vector< int > &output_connect_to_the_left, Vector< int > &output_connect_to_the_right)
Break any possible loop created by the sorted list of nodes that is used to create a new shared polyl...
Definition: triangle_mesh.template.cc:13103
oomph::Mesh::nboundary
unsigned nboundary() const
Return number of boundaries.
Definition: mesh.h:806
oomph::TriangulateIO::numberoftriangles
int numberoftriangles
Definition: unstructured_two_d_mesh_geometry_base.h:82
oomph::Multi_domain_functions::Counter_for_flat_packed_unsigneds
unsigned Counter_for_flat_packed_unsigneds
Counter used when processing vector of flat-packed unsigneds – this is really "private" data,...
Definition: multi_domain.cc:140
oomph::TriangleMeshCurveSection
Definition: unstructured_two_d_mesh_geometry_base.h:172
oomph::RefineableTriangleMesh::min_permitted_angle
double & min_permitted_angle()
Min angle before remesh gets triggered.
Definition: triangle_mesh.template.h:2381
oomph::RefineableTriangleMesh::update_other_proc_shd_bnd_node_helper
void update_other_proc_shd_bnd_node_helper(Node *&new_nod_pt, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, Vector< unsigned > &other_processor_1, Vector< unsigned > &other_processor_2, Vector< unsigned > &other_shared_boundaries, Vector< unsigned > &other_indexes, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function that assigns/updates the references to the node so that it can be found with any othe...
Definition: triangle_mesh.template.cc:20086
oomph::FiniteElement::interpolated_x
virtual double interpolated_x(const Vector< double > &s, const unsigned &i) const
Return FE interpolated coordinate x[i] at local coordinate s.
Definition: elements.cc:3881
oomph::TriangleMeshParameters::disable_automatic_creation_of_vertices_on_boundaries
void disable_automatic_creation_of_vertices_on_boundaries()
Definition: triangle_mesh.template.h:298
NonRefineableBinArray::get_bin
void get_bin(const Vector< double > &zeta, int &bin_number)
Get the number of the bin containing the specified coordinate. Bin number is negative if the coordina...
Definition: sample_point_container.cc:2803
oomph::TriangleMeshCurveSection::maximum_length
double maximum_length()
Gets access to the maximum length variable.
Definition: unstructured_two_d_mesh_geometry_base.h:304
oomph::TimeStepper::ntstorage
unsigned ntstorage() const
Return the number of doubles required to represent history (one for steady)
Definition: timesteppers.h:562
oomph::RefineableTriangleMesh::unrefine_shared_boundary_constrained_by_target_area
bool unrefine_shared_boundary_constrained_by_target_area(const unsigned &b, const unsigned &c, Vector< Vector< double > > &vector_bnd_vertices, Vector< double > &area_constraint)
Helper function that performs the unrefinement process on the specified boundary by using the provide...
Definition: triangle_mesh.template.cc:40667
oomph::TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values
void identify_boundary_segments_and_assign_initial_zeta_values(const unsigned &b, Vector< FiniteElement * > &input_face_ele_pt, const bool &is_internal_boundary, std::map< FiniteElement *, FiniteElement * > &face_to_bulk_element_pt)
Identify the segments from the old mesh (original mesh) in the new mesh (this) and assign initial and...
oomph::TriangleMeshPolyLine::boundary_chunk
unsigned boundary_chunk() const
Definition: unstructured_two_d_mesh_geometry_base.h:841
oomph::RefineableTriangleMesh::add_halo_element_helper
void add_halo_element_helper(unsigned &iproc, FiniteElement *ele_pt)
Helper function to create (halo) elements on the loop process based on the info received in send_and_...
Definition: triangle_mesh.template.cc:18963
oomph::AlgebraicNode::add_node_update_info
void add_node_update_info(const int &id, AlgebraicMesh *mesh_pt, const Vector< GeomObject * > &geom_object_pt, const Vector< double > &ref_value, const bool &called_from_constructor=false)
Add algebraic update information for node: What's the ID of the mesh update function (typically used ...
Definition: algebraic_elements.h:289
oomph::MeshAsGeomObject
Definition: mesh_as_geometric_object.h:99
oomph::ProjectionProblem::project
void project(Mesh *base_mesh_pt, const bool &dont_project_positions=false)
Project from base into the problem's own mesh.
Definition: projection.h:726
oomph::Data
A class that represents a collection of data; each Data object may contain many different individual ...
Definition: nodes.h:89
oomph::RefineableTriangleMesh::add_haloed_node_helper
void add_haloed_node_helper(unsigned &iproc, Node *nod_pt)
Helper function to add haloed node.
Definition: triangle_mesh.template.cc:18700
oomph::Data::non_halo_proc_ID
int non_halo_proc_ID()
ID of processor ID that holds non-halo counterpart of halo node; negative if not a halo.
Definition: nodes.h:494
oomph::Global_timings::Doc_comprehensive_timings
bool Doc_comprehensive_timings
Global boolean to switch on comprehensive timing – can probably be declared const false when developm...
Definition: oomph_definitions.cc:56
oomph::TriangulateIO::pointmarkerlist
int * pointmarkerlist
Pointer to list of point markers.
Definition: unstructured_two_d_mesh_geometry_base.h:74
oomph::RefineableTriangleMesh::add_element_load_balance_helper
void add_element_load_balance_helper(const unsigned &iproc, Vector< Vector< std::map< unsigned, FiniteElement * > > > &received_old_haloed_element_pt, FiniteElement *ele_pt)
Helper function to create elements on the loop process based on the info received in send_and_receive...
Definition: triangle_mesh.template.cc:27316
oomph::UnstructuredTwoDMeshGeometryBase::boundary_element_in_region_pt
FiniteElement * boundary_element_in_region_pt(const unsigned &b, const unsigned &r, const unsigned &e) const
Return pointer to the e-th element adjacent to boundary b in region r.
Definition: unstructured_two_d_mesh_geometry_base.h:1772
oomph::Multi_domain_functions::Doc_full_stats
bool Doc_full_stats
Boolean to indicate whether to output further info during setup_multi_domain_interaction() routines.
Definition: multi_domain.cc:172
oomph::TriangleMeshParameters::set_communicator_pt
void set_communicator_pt(OomphCommunicator *comm_pt)
Function to set communicator (mesh is then assumed to be distributed)
Definition: triangle_mesh.template.h:264
oomph::UnstructuredTwoDMeshGeometryBase::nregion
unsigned nregion()
Return the number of regions specified by attributes.
Definition: unstructured_two_d_mesh_geometry_base.h:1636
oomph::TriangulateIO::numberofsegments
int numberofsegments
Definition: unstructured_two_d_mesh_geometry_base.h:88
oomph::Node::resize
void resize(const unsigned &n_value)
Resize the number of equations.
Definition: nodes.cc:2089
oomph::TriangleMeshOpenCurve
Definition: unstructured_two_d_mesh_geometry_base.h:1512
oomph::Missing_masters_functions::get_required_nodal_information_helper
void get_required_nodal_information_helper(int &iproc, Node *nod_pt, Mesh *const &mesh_pt, int &n_cont_inter_values, Vector< unsigned > &send_unsigneds, Vector< double > &send_doubles)
Helper function to get the required nodal information from an external haloed node so that a fully-fu...
Definition: missing_masters.cc:439
oomph::FaceElementAsGeomObject
Definition: face_element_as_geometric_object.h:64
oomph::TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary
void re_scale_re_assigned_initial_zeta_values_for_internal_boundary(const unsigned &b)
Re-scale the re-assigned zeta values for the boundary nodes, apply only for internal boundaries.
Definition: triangle_mesh.template.cc:6446
oomph::RefineableTriangleMesh::update_polygon_after_restart
void update_polygon_after_restart(TriangleMeshPolygon *&polygon_pt)
Updates the polylines representation after restart.
Definition: triangle_mesh.template.cc:40981
oomph::RefineableTriangleMesh::reset_halo_haloed_scheme_helper
void reset_halo_haloed_scheme_helper(Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, Vector< Vector< Node * > > &iproc_currently_created_nodes_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
In charge of creating additional halo(ed) elements on those processors that have no shared boundaries...
Definition: triangle_mesh.template.cc:17463
oomph::FiniteElement::construct_node
virtual Node * construct_node(const unsigned &n)
Construct the local node n and return a pointer to the newly created node object.
Definition: elements.h:2409
oomph::TriangulateIO::pointlist
double * pointlist
Pointer to list of points x coordinate followed by y coordinate.
Definition: unstructured_two_d_mesh_geometry_base.h:68
oomph::RefineableTriangleMesh::update_open_curve_using_face_mesh
bool update_open_curve_using_face_mesh(TriangleMeshOpenCurve *open_polyline_pt, const bool &check_only=false)
Helper function that updates the input open curve by using end-points of elements from FaceMesh(es) t...
Definition: triangle_mesh.template.cc:34366
oomph::SolidNode::variable_position_pt
Data *const & variable_position_pt() const
Pointer to variable_position data (const version)
Definition: nodes.h:1654
oomph::TriangleMeshCurveSection::boundary_id
virtual unsigned boundary_id() const =0
Boundary id.
oomph::RefineableTriangleMesh::create_temporary_boundary_connections
void create_temporary_boundary_connections(Vector< TriangleMeshPolygon * > &tmp_outer_polygons_pt, Vector< TriangleMeshOpenCurve * > &tmp_open_curves_pt)
After unrefinement and refinement has taken place compute the new vertices numbers of the temporary r...
Definition: triangle_mesh.template.cc:32761
oomph::SolidMesh
General SolidMesh class.
Definition: mesh.h:2487
oomph::DocInfo::disable_doc
void disable_doc()
Disable documentation.
Definition: oomph_utilities.h:593
oomph::TriangulateIO::numberofholes
int numberofholes
Definition: unstructured_two_d_mesh_geometry_base.h:91
oomph::TriangulateIO::segmentmarkerlist
int * segmentmarkerlist
Definition: unstructured_two_d_mesh_geometry_base.h:87
oomph::GeomObject
Definition: geom_objects.h:105
oomph::DummyFaceElement
Definition: elements.h:4858
oomph::RefineableTriangleMesh::refine_shared_boundary_constrained_by_target_area
bool refine_shared_boundary_constrained_by_target_area(Vector< Vector< double > > &vector_bnd_vertices, Vector< double > &area_constraint)
Helper function that performs the refinement process on the specified boundary by using the provided ...
Definition: triangle_mesh.template.cc:40877
oomph::TriangleMesh::boundary_segment_node_pt
Vector< Vector< Node * > > & boundary_segment_node_pt(const unsigned &b)
Return direct access to nodes associated with a boundary but sorted in segments.
Definition: triangle_mesh.template.h:908
oomph::RefineableTriangleMesh::send_and_receive_elements_nodes_info
void send_and_receive_elements_nodes_info(int &send_proc, int &recv_proc)
Helper function to send back halo and haloed information.
Definition: triangle_mesh.template.cc:18753
oomph::RefineableTriangleMesh::get_boundary_segment_nodes_helper
void get_boundary_segment_nodes_helper(const unsigned &b, Vector< Vector< Node * > > &tmp_segment_nodes)
Get the nodes on the boundary (b), these are stored in the segment they belong (also used by the load...
Definition: triangle_mesh.template.cc:28824
oomph::TriangleMesh::get_element_edges_on_boundary
void get_element_edges_on_boundary(std::map< std::pair< Node *, Node * >, unsigned > &element_edges_on_boundary)
Get the element edges (pair of nodes, edges) that lie on a boundary (used to mark shared boundaries t...
Definition: triangle_mesh.template.cc:11574
oomph::TriangleMeshCurveSection::final_vertex_connected_n_chunk
unsigned final_vertex_connected_n_chunk() const
Gets the boundary chunk to which the final end is connected.
Definition: unstructured_two_d_mesh_geometry_base.h:472
oomph::UnstructuredTwoDMeshGeometryBase::nboundary_segment_node
unsigned long nboundary_segment_node(const unsigned &b)
Return the number of segments associated with a boundary.
Definition: unstructured_two_d_mesh_geometry_base.h:1902
oomph::TriangleMeshCurveSection::suspend_final_vertex_connected
void suspend_final_vertex_connected()
Definition: unstructured_two_d_mesh_geometry_base.h:410
oomph::TriangleMesh::Point::x
coord_t x
Definition: triangle_mesh.template.h:2101
oomph::RefineableTriangleMesh::adapt
void adapt(const Vector< double > &elem_error)
Adapt mesh, based on elemental error provided.
Definition: triangle_mesh.template.cc:29348
oomph::UnstructuredTwoDMeshGeometryBase::boundary_segment_initial_arclength
std::map< unsigned, Vector< double > > & boundary_segment_initial_arclength()
Return direct access to the initial arclength for the segments that are part of a boundary.
Definition: unstructured_two_d_mesh_geometry_base.h:2002
oomph::Mesh::set_nodal_and_elemental_time_stepper
void set_nodal_and_elemental_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Set the timestepper associated with all nodal and elemental data stored in the mesh.
Definition: mesh.h:1003
oomph::TriangleMesh::reset_boundary_element_info
virtual void reset_boundary_element_info(Vector< unsigned > &ntmp_boundary_elements, Vector< Vector< unsigned > > &ntmp_boundary_elements_in_region, Vector< FiniteElement * > &deleted_elements)
Reset the boundary elements info. after load balance have taken place.
Definition: triangle_mesh.template.cc:14691
oomph::TimingHelpers::timer
double timer()
returns the time in seconds after some point in past
Definition: oomph_utilities.cc:1642
oomph::MacroElementNodeUpdateMesh::geom_object_vector_pt
Vector< GeomObject * > geom_object_vector_pt()
Access function to the vector of GeomObject.
Definition: macro_element_node_update_element.h:539
oomph::Mesh
A general mesh class.
Definition: mesh.h:74
oomph::Mesh::node_pt
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
Definition: mesh.h:456
oomph::TriangleMesh::create_polylines_from_halo_elements_helper
void create_polylines_from_halo_elements_helper(const Vector< unsigned > &element_domain, std::map< GeneralisedElement *, unsigned > &element_to_global_index, std::set< FiniteElement * > &element_in_processor_pt, Vector< Vector< Vector< GeneralisedElement * > > > &input_halo_elements, std::map< std::pair< Node *, Node * >, unsigned > &elements_edges_on_boundary, Vector< Vector< Vector< TriangleMeshPolyLine * > > > &output_polylines_pt)
Creates polylines from the intersection of halo elements on all processors. The new polylines define ...
Definition: triangle_mesh.template.cc:11640
oomph::TriangleMesh::Point::y
coord_t y
Definition: triangle_mesh.template.h:2101
oomph::TriangleMeshPolyLine::reverse
void reverse()
Definition: unstructured_two_d_mesh_geometry_base.h:874
oomph::RefineableTriangleMesh::apply_max_length_constraint
bool apply_max_length_constraint(Mesh *face_mesh_pt, Vector< Vector< double > > &vector_bnd_vertices, double &max_length_constraint)
Definition: triangle_mesh.template.cc:35283
oomph::RefineableTriangleMesh::add_received_node_load_balance_helper
void add_received_node_load_balance_helper(Node *&new_nod_pt, Vector< Vector< FiniteElement * > > &f_haloed_ele_pt, Vector< Vector< std::map< unsigned, FiniteElement * > > > &received_old_haloed_element_pt, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function to add a new node from load balance.
Definition: triangle_mesh.template.cc:27581
oomph::Data::nvalue
unsigned nvalue() const
Return number of values stored in data object (incl pinned ones).
Definition: nodes.h:448
oomph::TriangleMesh::output_boundary_coordinates
void output_boundary_coordinates(const unsigned &b, std::ostream &outfile)
Definition: triangle_mesh.template.cc:7906
oomph::TriangleMeshCurveSection::initial_vertex_connected_n_vertex
unsigned initial_vertex_connected_n_vertex() const
Gets the vertex number to which the initial end is connected.
Definition: unstructured_two_d_mesh_geometry_base.h:440
oomph::RefineableTriangleMesh::create_sorted_face_mesh_representation
void create_sorted_face_mesh_representation(const unsigned &boundary_id, Mesh *face_mesh_pt, std::map< FiniteElement *, bool > &is_inverted, bool &inverted_face_mesh)
Helper function Creates a sorted face mesh representation of the specified PolyLine It means that the...
Definition: triangle_mesh.template.cc:35438
oomph::AlgebraicMesh::geom_object_list_pt
GeomObject * geom_object_list_pt(const unsigned &i)
Access function to the ith GeomObject.
Definition: algebraic_elements.h:879
oomph::RefineableTriangleMesh
Unstructured refineable Triangle Mesh.
Definition: triangle_mesh.template.h:2158
oomph::UnstructuredTwoDMeshGeometryBase::region_element_pt
FiniteElement * region_element_pt(const unsigned &i, const unsigned &e)
Return the e-th element in the i-th region.
Definition: unstructured_two_d_mesh_geometry_base.h:1662
oomph::GeneralisedTimeStepper
Generalised timestepper that can serve a variety of purposes in continuation, bifurcation detection a...
Definition: generalised_timesteppers.h:55
oomph::RefineableTriangleMesh::resume_boundary_connections
void resume_boundary_connections(Vector< TriangleMeshPolyLine * > &resume_initial_connection_polyline_pt, Vector< TriangleMeshPolyLine * > &resume_final_connection_polyline_pt)
Resume the boundary connections that may have been suspended because the destination boundary is no p...
Definition: triangle_mesh.template.cc:33778
oomph::TriangleMeshPolyLine::vertex_coordinate
Vector< double > vertex_coordinate(const unsigned &i) const
Coordinate vector of i-th vertex (const version)
Definition: unstructured_two_d_mesh_geometry_base.h:844
oomph::TriangleMeshCurveSection::set_unrefinement_tolerance
void set_unrefinement_tolerance(const double &tolerance)
Set tolerance for unrefinement of curve sections to avoid unnecessarily large numbers of elements on ...
Definition: unstructured_two_d_mesh_geometry_base.h:272
oomph::AlgebraicNode::ngeom_object
unsigned ngeom_object(const int &id)
Number of geometric objects involved in id-th update function.
Definition: algebraic_elements.h:199
oomph::RefineableTriangleMesh::min_element_size
double & min_element_size()
Min element size allowed during adaptation.
Definition: triangle_mesh.template.h:2378
oomph::TriangleMesh::break_loops_on_shared_polyline_load_balance_helper
void break_loops_on_shared_polyline_load_balance_helper(const unsigned &initial_shd_bnd_id, std::list< Node * > &input_nodes, Vector< FiniteElement * > &input_boundary_element_pt, Vector< FiniteElement * > &input_boundary_face_element_pt, Vector< int > &input_face_index_element, const int &input_connect_to_the_left, const int &input_connect_to_the_right, Vector< std::list< Node * > > &output_sorted_nodes_pt, Vector< Vector< FiniteElement * > > &output_boundary_element_pt, Vector< Vector< FiniteElement * > > &output_boundary_face_element_pt, Vector< Vector< int > > &output_face_index_element, Vector< int > &output_connect_to_the_left, Vector< int > &output_connect_to_the_right)
Break any possible loop created by the sorted list of nodes that is used to create a new shared polyl...
Definition: triangle_mesh.template.cc:14023
oomph::MacroElementNodeUpdateMesh
Definition: macro_element_node_update_element.h:378
oomph::RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper
void get_shared_boundary_segment_nodes_helper(const unsigned &shd_bnd_id, Vector< Vector< Node * > > &tmp_segment_nodes)
Get the nodes on the shared boundary (b), these are stored in the segment they belong.
Definition: triangle_mesh.template.cc:25777
oomph::Mesh::boundary_element_pt
FiniteElement * boundary_element_pt(const unsigned &b, const unsigned &e) const
Return pointer to e-th finite element on boundary b.
Definition: mesh.h:814
boundaries
in the role of the member functions c Node::position() and \c Node the latter case arises if the c Node is located on edges and corners of the mesh Storage of this information facilitates the automatic determination of boundary conditions for new c Nodes that are created during mesh refinement n The majority of the c Nodes will b not be located on boundaries
Definition: the_data_structure.txt:201
oomph::Problem::add_time_stepper_pt
void add_time_stepper_pt(TimeStepper *const &time_stepper_pt)
Add a timestepper to the problem. The function will automatically create or resize the Time object so...
Definition: problem.cc:1535
oomph::FiniteElement::local_coordinate_of_node
virtual void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Get local coordinates of node j in the element; vector sets its own size (broken virtual)
Definition: elements.h:1820
oomph::ToleranceForVertexMismatchInPolygons::Tolerable_error
double Tolerable_error
Acceptable discrepancy for mismatch in vertex coordinates. In paranoid mode, the code will die if the...
Definition: unstructured_two_d_mesh_geometry_base.cc:1107
oomph::GeneralisedElement::non_halo_proc_ID
int non_halo_proc_ID()
ID of processor ID that holds non-halo counterpart of halo element; negative if not a halo.
Definition: elements.h:1162
oomph::TriangulateIO::numberofcorners
int numberofcorners
Definition: unstructured_two_d_mesh_geometry_base.h:83
oomph::TriangleMeshParameters::regions_coordinates
std::map< unsigned, Vector< double > > & regions_coordinates()
Helper function for getting access to the regions coordinates.
Definition: triangle_mesh.template.h:234
oomph::RefineableTriangleMesh::construct_new_node_load_balance_helper
void construct_new_node_load_balance_helper(Node *&new_nod_pt, Vector< Vector< FiniteElement * > > &f_haloed_ele_pt, Vector< Vector< std::map< unsigned, FiniteElement * > > > &received_old_haloed_element_pt, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function which constructs a new node (on an element) with the information sent from the load b...
Definition: triangle_mesh.template.cc:27652
oomph::Mesh::flush_node_storage
void flush_node_storage()
Flush storage for nodes (only) by emptying the vectors that store the pointers to them.
Definition: mesh.h:450
oomph::ProjectionProblem::disable_use_iterative_solver_for_projection
void disable_use_iterative_solver_for_projection()
Disbales the use of an iterative solver for projection.
Definition: projection.h:722
t
char t
Definition: cfortran.h:572
oomph::TriangleMeshCurveSection::connect_initial_vertex_to_polyline
void connect_initial_vertex_to_polyline(TriangleMeshPolyLine *polyline_pt, const unsigned &vertex_number, const double &tolerance_for_connection=1.0e-14)
Connects the initial vertex of the curve section to a desired target polyline by specifying the verte...
Definition: unstructured_two_d_mesh_geometry_base.cc:1124
oomph::SamplePointContainerParameters::enable_use_eulerian_coordinates_during_setup
void enable_use_eulerian_coordinates_during_setup()
Definition: sample_point_parameters.h:154
oomph::Mesh::nboundary_element
unsigned nboundary_element(const unsigned &b) const
Return number of finite elements that are adjacent to boundary b.
Definition: mesh.h:852
oomph::TriangleMesh::dump_distributed_info_for_restart
void dump_distributed_info_for_restart(std::ostream &dump_file)
Used to dump info. related with distributed triangle meshes.
Definition: triangle_mesh.template.cc:7323
oomph::AlgebraicNode::node_update_fct_id
int node_update_fct_id()
Default (usually first if there are multiple ones) node update fct id.
Definition: algebraic_elements.h:161
oomph::TriangulateIO
Definition: unstructured_two_d_mesh_geometry_base.h:65
oomph::BinArrayParameters::dimensions_of_bin_array
Vector< unsigned > & dimensions_of_bin_array()
Number of bins in each coordinate direction.
Definition: sample_point_parameters.h:314
oomph::TriangleMeshParameters
Helper object for dealing with the parameters used for the TriangleMesh objects.
Definition: triangle_mesh.template.h:100
oomph::RefineableTriangleMesh::update_polygon_using_face_mesh
bool update_polygon_using_face_mesh(TriangleMeshPolygon *polygon_pt, const bool &check_only=false)
Helper function that updates the input polygon's PSLG by using the end-points of elements from FaceMe...
Definition: triangle_mesh.template.cc:33880
value
often abbreviated as dof b History b value
Definition: the_data_structure.txt:44
oomph::RefineableTriangleMesh::add_halo_node_helper
void add_halo_node_helper(Node *&new_nod_pt, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function to add halo node.
Definition: triangle_mesh.template.cc:19132
oomph::TriangleMesh::build_from_scaffold
void build_from_scaffold(TimeStepper *time_stepper_pt, const bool &use_attributes)
Build mesh from scaffold.
Definition: triangle_mesh.template.cc:49
oomph::AlgebraicNode::ref_value
double ref_value(const unsigned &i)
Return i-th reference value involved in default (usually first) update function.
Definition: algebraic_elements.h:276
oomph::TriangleMeshPolygon::can_update_reference_configuration
bool can_update_reference_configuration() const
Test whether curve can update reference.
Definition: unstructured_two_d_mesh_geometry_base.h:1452
oomph::Mesh::add_element_pt
void add_element_pt(GeneralisedElement *const &element_pt)
Add a (pointer to) an element to the mesh.
Definition: mesh.h:605
oomph::TriangleMeshCurveSection::initial_vertex_connected_n_chunk
unsigned initial_vertex_connected_n_chunk() const
Gets the boundary chunk to which the initial end is connected.
Definition: unstructured_two_d_mesh_geometry_base.h:448
oomph::TriangleMesh::shared_boundary_overlaps_internal_boundary
const bool shared_boundary_overlaps_internal_boundary(const unsigned &shd_bnd_id)
Checks if the shared boundary overlaps an internal boundary.
Definition: triangle_mesh.template.h:1665
oomph::TriangleMesh::sort_polylines_helper
void sort_polylines_helper(Vector< TriangleMeshPolyLine * > &unsorted_polylines_pt, Vector< Vector< TriangleMeshPolyLine * > > &sorted_polylines_pt)
Sorts the polylines so they be continuous and then we can create a closed or open curve from them.
Definition: triangle_mesh.template.cc:11217
oomph::Node::x
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition: nodes.h:994
oomph::TriangleMeshPolyLine::boundary_id
unsigned boundary_id() const
Boundary id.
Definition: unstructured_two_d_mesh_geometry_base.h:837
oomph::TimeStepper
Base class for time-stepping schemes. Timestepper provides an approximation of the temporal derivativ...
Definition: timesteppers.h:219
oomph::Node::get_boundaries_pt
virtual void get_boundaries_pt(std::set< unsigned > *&boundaries_pt)
Return a pointer to set of mesh boundaries that this node occupies; this will be overloaded by Bounda...
Definition: nodes.h:1283
oomph::RefineableSolidTriangleMesh
Unstructured refineable Triangle Mesh upgraded to solid mesh.
Definition: triangle_mesh.template.h:3824
oomph::RefineableTriangleMesh::create_halo_element
void create_halo_element(unsigned &iproc, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function to create (halo) elements on the loop process based on the info received in send_and_...
Definition: triangle_mesh.template.cc:18871
oomph::TriangulateIO::trianglearealist
double * trianglearealist
Definition: unstructured_two_d_mesh_geometry_base.h:80
oomph::TriangleMesh::oomph_vertex_nodes_id
Vector< unsigned > oomph_vertex_nodes_id()
Return the vector that contains the oomph-lib node number for all vertex nodes in the TriangulateIO r...
Definition: triangle_mesh.template.h:1122
oomph::GeneralisedElement
A Generalised Element class.
Definition: elements.h:76
oomph::TriangleMeshClosedCurve::internal_point
Vector< double > internal_point() const
Coordinates of the internal point.
Definition: unstructured_two_d_mesh_geometry_base.h:1303
oomph::Node::set_non_obsolete
void set_non_obsolete()
Mark node as non-obsolete.
Definition: nodes.h:1350
oomph::SolidNode
A Class for nodes that deform elastically (i.e. position is an unknown in the problem)....
Definition: nodes.h:1568
oomph::TriangleMeshBase::triangulateio_representation
TriangulateIO & triangulateio_representation()
Access to the triangulateio representation of the mesh.
Definition: triangle_mesh.h:121
oomph::Node::value
double value(const unsigned &i) const
Return i-th value (dofs or pinned) at this node either directly or via hanging node representation....
Definition: nodes.cc:2328
oomph::Mesh::flush_element_and_node_storage
void flush_element_and_node_storage()
Flush storage for elements and nodes by emptying the vectors that store the pointers to them....
Definition: mesh.h:427
oomph::AlgebraicNode::geom_object_pt
GeomObject * geom_object_pt(const unsigned &i)
Return pointer to i-th geometric object involved in default (usually first) update function.
Definition: algebraic_elements.h:238
oomph::TriangleMeshCurveSection::set_initial_vertex_connected
void set_initial_vertex_connected()
Sets the initial vertex as connected.
Definition: unstructured_two_d_mesh_geometry_base.h:360
oomph::TriangleMeshCurveSection::is_initial_vertex_connected
bool is_initial_vertex_connected() const
Test whether initial vertex is connected or not.
Definition: unstructured_two_d_mesh_geometry_base.h:356
oomph::TriangleMeshPolyLine::initial_vertex_coordinate
void initial_vertex_coordinate(Vector< double > &vertex)
Get first vertex coordinates.
Definition: unstructured_two_d_mesh_geometry_base.h:852
oomph::TriangleHelper::initialise_triangulateio
void initialise_triangulateio(TriangulateIO &triangle_io)
Initialise TriangulateIO structure.
Definition: unstructured_two_d_mesh_geometry_base.cc:93
oomph::NonRefineableBinArrayParameters
Helper object for dealing with the parameters used for the NonRefineableBinArray objects.
Definition: sample_point_parameters.h:508
oomph
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
Definition: advection_diffusion_elements.cc:33
oomph::RefineableTriangleMesh::compute_shared_node_degree_helper
void compute_shared_node_degree_helper(Vector< Vector< FiniteElement * > > &unsorted_face_ele_pt, std::map< Node *, unsigned > &global_node_degree)
Computes the degree of the nodes on the shared boundaries, the degree of the node is computed from th...
Definition: triangle_mesh.template.cc:24593
oomph::FiniteElement::nnode
unsigned nnode() const
Return the number of nodes.
Definition: elements.h:2163
oomph::Node
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:851
oomph::TriangleHelper::deep_copy_of_triangulateio_representation
TriangulateIO deep_copy_of_triangulateio_representation(TriangulateIO &triangle_io, const bool &quiet)
Make (partial) deep copy of TriangulateIO object. We only copy those items we need within oomph-lib's...
Definition: unstructured_two_d_mesh_geometry_base.cc:136
oomph::RefineableTriangleMesh::get_required_nodal_information_helper
void get_required_nodal_information_helper(unsigned &iproc, Node *nod_pt)
Helper function to get the required nodal information from a haloed node so that a fully-functional h...
Definition: triangle_mesh.template.cc:18121
oomph::Vector
Definition: Vector.h:63
oomph::AlgebraicMesh
Definition: algebraic_elements.h:635
oomph::TriangleMeshCurveSection::connect_final_vertex_to_polyline
void connect_final_vertex_to_polyline(TriangleMeshPolyLine *polyline_pt, const unsigned &vertex_number, const double &tolerance_for_connection=1.0e-14)
Connects the final vertex of the curve section to a desired target polyline by specifying the vertex ...
Definition: unstructured_two_d_mesh_geometry_base.cc:1194
oomph::RefineableTriangleMesh::get_face_mesh_representation
void get_face_mesh_representation(TriangleMeshPolygon *polygon_pt, Vector< Mesh * > &face_mesh_pt)
Helper function to construct face mesh representation of all polylines, possibly with segments re-dis...
Definition: triangle_mesh.template.cc:35635
oomph::Node::is_on_boundary
virtual bool is_on_boundary() const
Test whether the Node lies on a boundary. The "bulk" Node cannot lie on a boundary,...
Definition: nodes.h:1289
oomph::UnstructuredTwoDMeshGeometryBase::boundary_segment_final_zeta
std::map< unsigned, Vector< double > > & boundary_segment_final_zeta()
Return direct access to the final zeta for the segments that are part of a boundary.
Definition: unstructured_two_d_mesh_geometry_base.h:2023
oomph::TriangleMeshParameters::element_area
double element_area() const
Helper function for getting the element area.
Definition: triangle_mesh.template.h:180
oomph::TriangleMesh::build_triangulateio
void build_triangulateio(const std::string &poly_file_name, TriangulateIO &triangulate_io, bool &use_attributes)
Helper function to create TriangulateIO object (return in triangulate_io) from the ....
Definition: triangle_mesh.template.cc:7083
oomph::SolidNode::add_values_to_vector
void add_values_to_vector(Vector< double > &vector_of_values)
Add all data, position and time history values to the vector Overload to add the Lagrangian coordinat...
Definition: nodes.cc:3603
oomph::TriangulateIO::segmentlist
int * segmentlist
Definition: unstructured_two_d_mesh_geometry_base.h:86
oomph::UnstructuredTwoDMeshGeometryBase::boundary_segment_final_coordinate
std::map< unsigned, Vector< Vector< double > > > & boundary_segment_final_coordinate()
Return direct access to the final coordinates for the segments that are part of a boundary.
Definition: unstructured_two_d_mesh_geometry_base.h:1995
oomph::UnstructuredTwoDMeshGeometryBase::nboundary_segment
unsigned nboundary_segment(const unsigned &b)
Return the number of segments associated with a boundary.
Definition: unstructured_two_d_mesh_geometry_base.h:1896
oomph::TriangleMesh::compute_holes_left_by_halo_elements_helper
void compute_holes_left_by_halo_elements_helper(Vector< Vector< double > > &output_holes_coordinates)
Compute the holes left by the halo elements, those adjacent to the shared boundaries.
Definition: triangle_mesh.template.cc:10690
oomph::TriangleMeshCurve::curve_section_pt
virtual TriangleMeshCurveSection * curve_section_pt(const unsigned &i) const
Pointer to i-th constituent curve section.
Definition: unstructured_two_d_mesh_geometry_base.h:1213
oomph::TriangleMeshCurveSection::nvertex
virtual unsigned nvertex() const =0
Number of vertices.
oomph::classcomp::operator()
bool operator()(const std::pair< double, double > &lhs, const std::pair< double, double > &rhs) const
Definition: triangle_mesh.template.cc:15041
oomph::TriangleMeshCurveSection::set_refinement_tolerance
void set_refinement_tolerance(const double &tolerance)
Set tolerance for refinement of curve sections to create a better representation of curvilinear bound...
Definition: unstructured_two_d_mesh_geometry_base.h:230
i
cstr elem_len * i
Definition: cfortran.h:607
oomph::TriangleMeshCurveSection::is_final_vertex_connected
bool is_final_vertex_connected() const
Test whether final vertex is connected or not.
Definition: unstructured_two_d_mesh_geometry_base.h:394
oomph::Node::ndim
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
Definition: nodes.h:991
oomph::ProjectionProblem
Definition: projection.h:680
oomph::TriangleMesh::synchronize_boundary_coordinates
void synchronize_boundary_coordinates(const unsigned &b)
In charge of sinchronize the boundary coordinates for internal boundaries that were split as part of ...
Definition: triangle_mesh.template.cc:5584
oomph::TriangleMesh::set_mesh_level_time_stepper
void set_mesh_level_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Overload set_mesh_level_time_stepper so that the stored time stepper now corresponds to the new times...
Definition: triangle_mesh.template.h:849
oomph::RefineableTriangleMesh::create_adjacency_matrix_new_shared_edges_helper
void create_adjacency_matrix_new_shared_edges_helper(Vector< Vector< FiniteElement * > > &unsorted_face_ele_pt, Vector< Vector< Node * > > &tmp_sorted_shared_node_pt, std::map< Node *, Vector< Vector< unsigned > > > &node_alias, Vector< Vector< Vector< unsigned > > > &adjacency_matrix)
Sort the nodes on the new shared boundaries (after load balancing), computes the alias of the nodes a...
Definition: triangle_mesh.template.cc:25591
oomph::TriangleMeshParameters::enable_use_attributes
void enable_use_attributes()
Helper function for enabling the use of attributes.
Definition: triangle_mesh.template.h:248
oomph::DocInfo
Information for documentation of results: Directory and file number to enable output in the form RESL...
Definition: oomph_utilities.h:562
oomph::RefineableTriangleMesh::refine_triangulateio
void refine_triangulateio(TriangulateIO &triangulate_io, const Vector< double > &target_area, TriangulateIO &triangle_refine)
Build a new TriangulateIO object from previous TriangulateIO based on target area for each element.
Definition: triangle_mesh.template.cc:14886
oomph::Multi_domain_functions::Doc_stats
bool Doc_stats
Boolean to indicate whether to output basic info during setup_multi_domain_interaction() routines.
Definition: multi_domain.cc:168
oomph::TriangleMesh::create_shared_polyline
void create_shared_polyline(const unsigned &my_rank, const unsigned &shd_bnd_id, const unsigned &iproc, const unsigned &jproc, std::list< Node * > &sorted_nodes, const int &root_edge_bnd_id, Vector< FiniteElement * > &bulk_bnd_ele_pt, Vector< int > &face_index_ele, Vector< Vector< TriangleMeshPolyLine * > > &unsorted_polylines_pt, const int &connect_to_the_left_flag, const int &connect_to_the_right_flag)
Create the shared polyline and fill the data structured that keep all the information associated with...
Definition: triangle_mesh.template.cc:14448
oomph::TriangleMeshPolygon::is_redistribution_of_segments_between_polylines_enabled
bool is_redistribution_of_segments_between_polylines_enabled()
Is re-distribution of polyline segments in the curve between different boundaries during adaptation e...
Definition: unstructured_two_d_mesh_geometry_base.h:1438
oomph::UnstructuredTwoDMeshGeometryBase::boundary_geom_object_pt
GeomObject * boundary_geom_object_pt(const unsigned &b)
Return the geometric object associated with the b-th boundary or null if the boundary has associated ...
Definition: unstructured_two_d_mesh_geometry_base.h:1707
oomph::RefineableTriangleMesh::compute_global_node_names_and_shared_nodes
void compute_global_node_names_and_shared_nodes(Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Compute the names of the nodes on shared boundaries in this (my_rank) processor with other processors...
Definition: triangle_mesh.template.cc:15898
oomph::AlgebraicNode
Definition: algebraic_elements.h:61
oomph::Multi_domain_functions::Doc_timings
bool Doc_timings
Boolean to indicate whether to doc timings or not.
Definition: multi_domain.cc:164
oomph::RefineableTriangleMesh::update_shared_curve_after_restart
void update_shared_curve_after_restart(Vector< TriangleMeshPolyLine * > &vector_polyline_pt)
Updates the shared polylines representation after restart.
Definition: triangle_mesh.template.cc:42680
oomph::TriangleMesh::create_shared_polylines_connections
void create_shared_polylines_connections()
Establish the connections of the polylines previously marked as having connections....
Definition: triangle_mesh.template.cc:9388
oomph::UnstructuredTwoDMeshGeometryBase::boundary_final_coordinate
std::map< unsigned, Vector< double > > & boundary_final_coordinate()
Return direct access to the final coordinates of a boundary.
Definition: unstructured_two_d_mesh_geometry_base.h:1958
oomph::TriangleMesh::shared_boundaries_ids
Vector< Vector< Vector< unsigned > > > shared_boundaries_ids() const
Definition: triangle_mesh.template.h:1392
oomph::TriangulateIO::triangleattributelist
double * triangleattributelist
Definition: unstructured_two_d_mesh_geometry_base.h:79
oomph::RefineableTriangleMesh::synchronize_shared_boundary_connections
const void synchronize_shared_boundary_connections()
Synchronise the vertices that are marked for non deletion.
Definition: triangle_mesh.template.cc:32412
n
endcode We introduce wrapper functions to access function so that we can formulate The Maths in generic terms Rather than referring to the pressure at node c n
Definition: the_data_structure.txt:582
oomph::Time
Class to keep track of discrete/continous time. It is essential to have a single Time object when usi...
Definition: timesteppers.h:67
oomph::TriangleMeshCurveSection::unrefinement_tolerance
double unrefinement_tolerance()
Get tolerance for unrefinement of curve section to create a better representation of curvilinear boun...
Definition: unstructured_two_d_mesh_geometry_base.h:281
oomph::TriangulateIO::holelist
double * holelist
Definition: unstructured_two_d_mesh_geometry_base.h:90
oomph::OomphLibWarning
Definition: oomph_definitions.h:266
oomph::TriangleMeshCurveSection::initial_vertex_connected_bnd_id
unsigned initial_vertex_connected_bnd_id() const
Gets the id to which the initial end is connected.
Definition: unstructured_two_d_mesh_geometry_base.h:432
oomph::MacroElementNodeUpdateNode
Definition: macro_element_node_update_element.h:54
oomph::RefineableTriangleMesh::send_boundary_node_info_of_shared_nodes
void send_boundary_node_info_of_shared_nodes(Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Get the original boundaries to which is associated each shared node, and send the info....
Definition: triangle_mesh.template.cc:16898
oomph::Mesh::face_index_at_boundary
int face_index_at_boundary(const unsigned &b, const unsigned &e) const
For the e-th finite element on boundary b, return int to indicate the face_index of the face adjacent...
Definition: mesh.h:870
oomph::MacroElementNodeUpdateNode::set_node_update_info
void set_node_update_info(FiniteElement *node_update_element_pt, const Vector< double > &s_in_node_update_element, const Vector< GeomObject * > &geom_object_pt)
Set node update information for node: Pass the pointer to the element that performs the update operat...
Definition: macro_element_node_update_element.h:170
oomph::UnstructuredTwoDMeshGeometryBase::boundary_initial_zeta_coordinate
std::map< unsigned, Vector< double > > & boundary_initial_zeta_coordinate()
Return direct access to the initial zeta coordinate of a boundary.
Definition: unstructured_two_d_mesh_geometry_base.h:1965
oomph::RefineableTriangleMesh::create_unsorted_face_mesh_representation
void create_unsorted_face_mesh_representation(const unsigned &boundary_id, Mesh *face_mesh_pt)
Helper function Creates an unsorted face mesh representation from the specified boundary id....
Definition: triangle_mesh.template.cc:35401
oomph::RefineableTriangleMesh::refine_boundary_constrained_by_target_area
bool refine_boundary_constrained_by_target_area(MeshAsGeomObject *mesh_geom_obj_pt, Vector< Vector< double > > &vector_bnd_vertices, double &refinement_tolerance, Vector< double > &area_constraint)
Helper function that performs the refinement process on the specified boundary by using the provided ...
Definition: triangle_mesh.template.cc:40523
oomph::RefineableTriangleMesh::add_non_delete_vertices_from_boundary_helper
void add_non_delete_vertices_from_boundary_helper(Vector< Vector< Node * > > src_bound_segment_node_pt, Vector< Vector< Node * > > dst_bound_segment_node_pt, const unsigned &dst_bnd_id, const unsigned &dst_bnd_chunk)
Adds the vertices from the sources boundary that are repeated in the destination boundary to the list...
Definition: triangle_mesh.template.cc:32325
oomph::TriangulateIO::pointattributelist
double * pointattributelist
Pointer to list of point attributes.
Definition: unstructured_two_d_mesh_geometry_base.h:71
oomph::TriangleHelper::clear_triangulateio
void clear_triangulateio(TriangulateIO &triangulate_io, const bool &clear_hole_data)
Clear TriangulateIO structure.
Definition: unstructured_two_d_mesh_geometry_base.cc:49
oomph::Bottom_left_sorter
struct oomph::classcomp Bottom_left_sorter
NonRefineableBinArray::fill_bin_by_diffusion
void fill_bin_by_diffusion(const unsigned &bin_diffusion_radius=1)
Fill bin by diffusion, populating each empty bin with the same content as the first non-empty bin fou...
Definition: sample_point_container.cc:2676
oomph::RefineableTriangleMesh::get_shared_boundary_elements_and_face_indexes
void get_shared_boundary_elements_and_face_indexes(const Vector< FiniteElement * > &first_element_pt, const Vector< FiniteElement * > &second_element_pt, Vector< FiniteElement * > &first_shared_boundary_element_pt, Vector< unsigned > &first_shared_boundary_element_face_index, Vector< FiniteElement * > &second_shared_boundary_element_pt, Vector< unsigned > &second_shared_boundary_element_face_index)
Use the first and second group of elements to find the intersection between them to get the shared bo...
Definition: triangle_mesh.template.cc:22311
oomph::Mesh::boundary_node_pt
Node *& boundary_node_pt(const unsigned &b, const unsigned &n)
Return pointer to node n on boundary b.
Definition: mesh.h:497
oomph::RefineableTriangleMesh::add_node_load_balance_helper
void add_node_load_balance_helper(unsigned &iproc, Vector< Vector< FiniteElement * > > &f_halo_ele_pt, Vector< Node * > &new_nodes_on_domain, Node *nod_pt)
Helper function to add haloed node.
Definition: triangle_mesh.template.cc:26475
NonRefineableBinArray::get_fill_stats
void get_fill_stats(unsigned &n_bin, unsigned &max_n_entry, unsigned &min_n_entry, unsigned &tot_n_entry, unsigned &n_empty) const
Provide some stats on the fill level of the associated bin.
Definition: sample_point_container.cc:2638
oomph::TriangleMeshPolyLine
Class defining a polyline for use in Triangle Mesh generation.
Definition: unstructured_two_d_mesh_geometry_base.h:791
oomph::Mesh::nelement
unsigned long nelement() const
Return number of elements in the mesh.
Definition: mesh.h:587
oomph::TriangleMeshPolyLine::nvertex
unsigned nvertex() const
Number of vertices.
Definition: unstructured_two_d_mesh_geometry_base.h:831
oomph::TriangleMeshPolygon
Class defining a closed polygon for the Triangle mesh generation.
Definition: unstructured_two_d_mesh_geometry_base.h:1337
oomph::RefineableTriangleMesh::construct_new_halo_node_helper
void construct_new_halo_node_helper(Node *&new_nod_pt, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function which constructs a new halo node (on an element) with the information sent from the h...
Definition: triangle_mesh.template.cc:19187
oomph::BoundaryNodeBase
A class that contains the information required by Nodes that are located on Mesh boundaries....
Definition: nodes.h:1854
u
Vector< double > u(3)
oomph::AlgebraicNode::nref_value
unsigned nref_value(const int &id)
Number of reference values involved in id-th update function.
Definition: algebraic_elements.h:244
oomph::TriangleMeshClosedCurve::is_internal_point_fixed
bool is_internal_point_fixed() const
Test whether the internal point is fixed.
Definition: unstructured_two_d_mesh_geometry_base.h:1317
oomph::TriangleMeshCurve::ncurve_section
virtual unsigned ncurve_section() const
Number of constituent curves.
Definition: unstructured_two_d_mesh_geometry_base.h:1084
oomph::TriangleMesh::create_shared_boundaries
void create_shared_boundaries(OomphCommunicator *comm_pt, const Vector< unsigned > &element_domain, const Vector< GeneralisedElement * > &backed_up_el_pt, const Vector< FiniteElement * > &backed_up_f_el_pt, std::map< Data *, std::set< unsigned > > &processors_associated_with_data, const bool &overrule_keep_as_halo_element_status)
Creates the shared boundaries.
Definition: triangle_mesh.template.cc:11410
oomph::RefineableTriangleMesh::create_element_load_balance_helper
void create_element_load_balance_helper(unsigned &iproc, Vector< Vector< FiniteElement * > > &f_haloed_ele_pt, Vector< Vector< std::map< unsigned, FiniteElement * > > > &received_old_haloed_element_pt, Vector< FiniteElement * > &new_elements_on_domain, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function to create elements on the loop process based on the info received in send_and_receive...
Definition: triangle_mesh.template.cc:27231
oomph::RefineableTriangleMesh::unrefine_boundary
bool unrefine_boundary(const unsigned &b, const unsigned &c, Vector< Vector< double > > &vector_bnd_vertices, double &unrefinement_tolerance, const bool &check_only=false)
Helper function that performs the unrefinement process.
Definition: triangle_mesh.template.cc:34848
oomph::TriangleMesh
Definition: triangle_mesh.template.h:369
oomph::FiniteElement::construct_boundary_node
virtual Node * construct_boundary_node(const unsigned &n)
Construct the local node n as a boundary node; that is a node that MAY be placed on a mesh boundary a...
Definition: elements.h:2437
oomph::Multi_domain_functions::Counter_for_flat_packed_doubles
unsigned Counter_for_flat_packed_doubles
Counter used when processing vector of flat-packed doubles – this is really "private" data,...
Definition: multi_domain.cc:118
oomph::AlgebraicMesh::ngeom_object_list_pt
unsigned ngeom_object_list_pt()
Return number of geometric objects associated with AlgebraicMesh.
Definition: algebraic_elements.h:873
oomph::classcomp
Definition: triangle_mesh.template.cc:15033
oomph::TriangleMeshCurveSection::suspend_initial_vertex_connected
void suspend_initial_vertex_connected()
Definition: unstructured_two_d_mesh_geometry_base.h:372
oomph::UnstructuredTwoDMeshGeometryBase::face_index_at_boundary_in_region
int face_index_at_boundary_in_region(const unsigned &b, const unsigned &r, const unsigned &e) const
Return face index of the e-th element adjacent to boundary b in region r.
Definition: unstructured_two_d_mesh_geometry_base.h:1790
e
e
Definition: cfortran.h:575
oomph::TriangleMeshCurveSection::resume_final_vertex_connected
void resume_final_vertex_connected()
Definition: unstructured_two_d_mesh_geometry_base.h:422
oomph::RefineableTriangleMesh::restore_boundary_connections
void restore_boundary_connections(Vector< TriangleMeshPolyLine * > &resume_initial_connection_polyline_pt, Vector< TriangleMeshPolyLine * > &resume_final_connection_polyline_pt)
After unrefinement and refinement has taken place compute the new vertices numbers of the boundaries ...
Definition: triangle_mesh.template.cc:32888
oomph::Missing_masters_functions::Flat_packed_unsigneds_string
Vector< std::string > Flat_packed_unsigneds_string
Definition: missing_masters.cc:61
oomph::TriangleMeshCurveSection::boundary_chunk
virtual unsigned boundary_chunk() const =0
oomph::TriangleMesh::read_distributed_info_for_restart
void read_distributed_info_for_restart(std::istream &restart_file)
Used to read info. related with distributed triangle meshes.
Definition: triangle_mesh.template.cc:7570
oomph::UnstructuredTwoDMeshGeometryBase::boundary_initial_coordinate
std::map< unsigned, Vector< double > > & boundary_initial_coordinate()
Return direct access to the initial coordinates of a boundary.
Definition: unstructured_two_d_mesh_geometry_base.h:1952
a
often abbreviated as dof b History b history values are but b not b the values at previous timesteps b Pinned c c c Mesh and c Problem subsection data Data The most elementary data structure in c oomph lib is c these values fall into two and those that must be determined as part of the solution c Data stores a value a double precision number the values of the unknowns are determined by the solution of a system of algebraic equations The solution of this system usually requires a(linear) numbering of the unknowns and associated equations. Hence
oomph::TriangleMesh::check_connections_of_polyline_nodes
const int check_connections_of_polyline_nodes(std::set< FiniteElement * > &element_in_processor_pt, const int &root_edge_bnd_id, std::map< std::pair< Node *, Node * >, bool > &overlapped_face, std::map< unsigned, std::map< Node *, bool > > &node_on_bnd_not_overlapped_by_shd_bnd, std::list< Node * > &current_polyline_nodes, std::map< unsigned, std::list< Node * > > &shared_bnd_id_to_sorted_list_node_pt, const unsigned &node_degree, Node *&new_node_pt, const bool called_from_load_balance=false)
Check for any possible connections that the array of sorted nodes have with any previous boundaries o...
Definition: triangle_mesh.template.cc:8949
oomph::TriangleMeshCurveSection::final_vertex_connected_bnd_id
unsigned final_vertex_connected_bnd_id() const
Gets the id to which the final end is connected.
Definition: unstructured_two_d_mesh_geometry_base.h:456
oomph::TriangleMesh::create_distributed_domain_representation
void create_distributed_domain_representation(Vector< TriangleMeshPolygon * > &polygons_pt, Vector< TriangleMeshOpenCurve * > &open_curves_pt)
Creates the distributed domain representation. Joins the original boundaires, shared boundaries and c...
Definition: triangle_mesh.template.cc:8021
oomph::GeneralisedElement::is_halo
bool is_halo() const
Is this element a halo?
Definition: elements.h:1158
oomph::TriangleMeshCurveSection::resume_initial_vertex_connected
void resume_initial_vertex_connected()
Definition: unstructured_two_d_mesh_geometry_base.h:384
oomph::TriangulateIO::numberoftriangleattributes
int numberoftriangleattributes
Definition: unstructured_two_d_mesh_geometry_base.h:84
oomph::Mesh::nboundary_node
unsigned long nboundary_node(const unsigned &ibound) const
Return number of nodes on a particular boundary.
Definition: mesh.h:809
oomph::FaceElement::set_boundary_number_in_bulk_mesh
void set_boundary_number_in_bulk_mesh(const unsigned &b)
Set function for the boundary number in bulk mesh.
Definition: elements.h:4366
oomph::RefineableTriangleMesh::update_polygon_using_elements_area
bool update_polygon_using_elements_area(TriangleMeshPolygon *&polygon_pt, const Vector< double > &target_area)
Updates the polylines using the elements area as constraint for the number of points along the bounda...
Definition: triangle_mesh.template.cc:37425
oomph::TBubbleEnrichedElement< 2, 3 >
oomph::UnstructuredTwoDMeshGeometryBase::boundary_final_zeta_coordinate
std::map< unsigned, Vector< double > > & boundary_final_zeta_coordinate()
Return direct access to the final zeta coordinates of a boundary.
Definition: unstructured_two_d_mesh_geometry_base.h:1972
oomph::RefineableTriangleMesh::get_connected_vertex_number_on_dst_boundary
bool get_connected_vertex_number_on_dst_boundary(Vector< double > &vertex_coordinates, const unsigned &dst_b_id, unsigned &vertex_number)
Computes the associated vertex number on the destination boundary.
Definition: triangle_mesh.template.cc:33824
oomph::RefineableTriangleMesh::add_vertices_for_non_deletion
void add_vertices_for_non_deletion()
Mark the vertices that are not allowed for deletion by the unrefienment/refinement polyline methods....
Definition: triangle_mesh.template.cc:31602
oomph::AlgebraicMesh::update_node_update
virtual void update_node_update(AlgebraicNode *&node_pt)=0
Update the node update info for given node, following mesh adaptation. Must be implemented for every ...
oomph::UnstructuredTwoDMeshGeometryBase::boundary_segment_initial_zeta
std::map< unsigned, Vector< double > > & boundary_segment_initial_zeta()
Return direct access to the initial zeta for the segments that are part of a boundary.
Definition: unstructured_two_d_mesh_geometry_base.h:2016
oomph::TriangleMeshCurveSection::refinement_tolerance
double refinement_tolerance()
Get tolerance for refinement of curve sections to create a better representation of curvilinear bound...
Definition: unstructured_two_d_mesh_geometry_base.h:239
oomph::TriangleMesh::Point
Definition: triangle_mesh.template.h:2100
oomph::TriangulateIO::numberofpointattributes
int numberofpointattributes
Definition: unstructured_two_d_mesh_geometry_base.h:76
oomph::UnstructuredTwoDMeshGeometryBase::boundary_segment_initial_coordinate
std::map< unsigned, Vector< Vector< double > > > & boundary_segment_initial_coordinate()
Return direct access to the initial coordinates for the segments that are part of a boundary.
Definition: unstructured_two_d_mesh_geometry_base.h:1987
oomph::Mesh::nnode
unsigned long nnode() const
Return number of nodes in the mesh.
Definition: mesh.h:590
s
static char t char * s
Definition: cfortran.h:572
oomph::TriangleMeshCurveSection::set_maximum_length
void set_maximum_length(const double &maximum_length)
Allows to specify the maximum distance between two vertices that define the associated polyline of th...
Definition: unstructured_two_d_mesh_geometry_base.h:295
oomph::RefineableTriangleMesh::unrefine_boundary_constrained_by_target_area
bool unrefine_boundary_constrained_by_target_area(const unsigned &b, const unsigned &c, Vector< Vector< double > > &vector_bnd_vertices, double &unrefinement_tolerance, Vector< double > &area_constraint)
Helper function that performs the unrefinement process on the specified boundary by using the provide...
Definition: triangle_mesh.template.cc:40268
oomph::TriangleMeshCurveSection::set_final_vertex_connected
void set_final_vertex_connected()
Sets the final vertex as connected.
Definition: unstructured_two_d_mesh_geometry_base.h:398
oomph::UnstructuredTwoDMeshGeometryBase::boundary_segment_final_arclength
std::map< unsigned, Vector< double > > & boundary_segment_final_arclength()
Return direct access to the final arclength for the segments that are part of a boundary.
Definition: unstructured_two_d_mesh_geometry_base.h:2009
oomph::CGALSamplePointContainerParameters
Helper object for dealing with the parameters used for the CGALSamplePointContainer objects.
Definition: sample_point_parameters.h:250
oomph::TriangleMeshParameters::extra_holes_coordinates
Vector< Vector< double > > extra_holes_coordinates() const
Helper function for getting the extra holes.
Definition: triangle_mesh.template.h:186
oomph::Problem::mesh_pt
Mesh *& mesh_pt()
Return a pointer to the global mesh.
Definition: problem.h:1271
oomph::TriangleMesh::create_tmp_open_curves_helper
void create_tmp_open_curves_helper(Vector< Vector< TriangleMeshPolyLine * > > &sorted_open_curves_pt, Vector< TriangleMeshPolyLine * > &unsorted_shared_to_internal_poly_pt, Vector< TriangleMeshOpenCurve * > &open_curves_pt)
Take the polylines from the original open curves and created new temporaly representations of open cu...
Definition: triangle_mesh.template.cc:8908
oomph::Global_string_for_annotation::string
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
Definition: oomph_definitions.cc:293
oomph::Multi_domain_functions::Flat_packed_doubles
Vector< double > Flat_packed_doubles
Vector of flat-packed doubles to be communicated with other processors.
Definition: multi_domain.cc:112
NonRefineableBinArray
NonRefineableBinArray class.
Definition: sample_point_container.h:855
oomph::TriangulateIO::regionlist
double * regionlist
Definition: unstructured_two_d_mesh_geometry_base.h:93
oomph::UnstructuredTwoDMeshGeometryBase::boundary_coordinate_limits
std::map< unsigned, Vector< double > > & boundary_coordinate_limits()
Return access to the vector of boundary coordinates associated with each geometric object.
Definition: unstructured_two_d_mesh_geometry_base.h:1729